Created
August 18, 2015 07:51
-
-
Save zaki50/231a91dfb71ff751fba6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/ActionBar.java appcampat-v7-23.0.0/android/support/v7/app/ActionBar.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/ActionBar.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/ActionBar.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -46,45 +46,38 @@ | |
* A primary toolbar within the activity that may display the activity title, application-level | |
* navigation affordances, 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. | |
+ * <p>The action bar appears at the top of an activity's window when the activity uses the | |
+ * AppCompat's {@link R.style#Theme_AppCompat AppCompat} theme (or one of its descendant themes). | |
* 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. | |
+ * AppCompatDelegate#requestWindowFeature(int) requestFeature(FEATURE_SUPPORT_ACTION_BAR)} or by | |
+ * declaring it in a custom theme with the {@link R.styleable#Theme_windowActionBar windowActionBar} | |
+ * property. | |
* </p> | |
* | |
- * <p>Beginning with Android L (API level 21), the action bar may be represented by any | |
- * Toolbar widget within the application layout. The application may signal to the Activity | |
- * which Toolbar should be treated as the Activity's action bar. Activities that use this | |
- * feature should use one of the supplied <code>.NoActionBar</code> themes, set the | |
- * {@link android.R.styleable#Theme_windowActionBar windowActionBar} attribute to <code>false</code> | |
+ * <p>The action bar may be represented by any Toolbar widget within the application layout. | |
+ * The application may signal to the Activity which Toolbar should be treated as the Activity's | |
+ * action bar. Activities that use this feature should use one of the supplied | |
+ * <code>.NoActionBar</code> themes, set the | |
+ * {@link R.styleable#Theme_windowActionBar windowActionBar} attribute to <code>false</code> | |
* or otherwise not request the window feature.</p> | |
* | |
- * <p>By adjusting the window features requested by the theme and the layouts used for | |
- * an Activity's content view, an app can use the standard system action bar on older platform | |
- * releases and the newer inline toolbars on newer platform releases. The <code>ActionBar</code> | |
- * object obtained from the Activity can be used to control either configuration transparently.</p> | |
+ * <p>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>When using the Holo themes 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>When using the Material themes (default in API 21 or newer) the navigation button | |
- * (formerly "Home") takes over the space previously occupied by the application icon. | |
- * Apps wishing to express a stronger branding should use their brand colors heavily | |
- * in the action bar and other application chrome or use a {@link #setLogo(int) logo} | |
+ * <p>The navigation button (formerly "Home") takes over the space previously occupied by the | |
+ * application icon. Apps wishing to express a stronger branding should use their brand colors | |
+ * heavily in the action bar and other application chrome or use a {@link #setLogo(int) logo} | |
* in place of their standard title text.</p> | |
* | |
* <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link | |
- * android.app.Activity#getActionBar getActionBar()}.</p> | |
+ * AppCompatActivity#getSupportActionBar()} getSupportActionBar()}.</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 | |
+ * using an {@link 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 | |
+ * same space, the {@link ActionMode} APIs are distinct and independent from those for | |
* {@link ActionBar}.</p> | |
* | |
* <div class="special reference"> | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/ActionBarDrawerToggle.java appcampat-v7-23.0.0/android/support/v7/app/ActionBarDrawerToggle.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/ActionBarDrawerToggle.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/ActionBarDrawerToggle.java 2015-07-26 08:18:46.000000000 +0900 | |
@@ -15,8 +15,8 @@ | |
*/ | |
package android.support.v7.app; | |
-import android.app.Activity; | |
import android.app.ActionBar; | |
+import android.app.Activity; | |
import android.content.Context; | |
import android.content.res.Configuration; | |
import android.content.res.TypedArray; | |
@@ -25,13 +25,12 @@ | |
import android.support.annotation.Nullable; | |
import android.support.annotation.StringRes; | |
import android.support.v4.view.GravityCompat; | |
-import android.support.v4.view.ViewCompat; | |
import android.support.v4.widget.DrawerLayout; | |
+import android.support.v7.graphics.drawable.DrawerArrowDrawable; | |
import android.support.v7.widget.Toolbar; | |
import android.util.Log; | |
import android.view.MenuItem; | |
import android.view.View; | |
-import android.support.v7.appcompat.R; | |
/** | |
* This class provides a handy way to tie together the functionality of | |
@@ -465,9 +464,7 @@ | |
return mActivityImpl.getThemeUpIndicator(); | |
} | |
- static class DrawerArrowDrawableToggle extends DrawerArrowDrawable | |
- implements DrawerToggle { | |
- | |
+ static class DrawerArrowDrawableToggle extends DrawerArrowDrawable implements DrawerToggle { | |
private final Activity mActivity; | |
public DrawerArrowDrawableToggle(Activity activity, Context themedContext) { | |
@@ -481,17 +478,11 @@ | |
} else if (position == 0f) { | |
setVerticalMirror(false); | |
} | |
- super.setProgress(position); | |
- } | |
- | |
- @Override | |
- boolean isLayoutRtl() { | |
- return ViewCompat.getLayoutDirection(mActivity.getWindow().getDecorView()) | |
- == ViewCompat.LAYOUT_DIRECTION_RTL; | |
+ setProgress(position); | |
} | |
public float getPosition() { | |
- return super.getProgress(); | |
+ return getProgress(); | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatActivity.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatActivity.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatActivity.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatActivity.java 2015-07-22 08:36:20.000000000 +0900 | |
@@ -19,6 +19,7 @@ | |
import android.content.Intent; | |
import android.content.res.Configuration; | |
import android.os.Bundle; | |
+import android.support.annotation.CallSuper; | |
import android.support.annotation.LayoutRes; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.ActivityCompat; | |
@@ -27,6 +28,7 @@ | |
import android.support.v4.app.TaskStackBuilder; | |
import android.support.v7.view.ActionMode; | |
import android.support.v7.widget.Toolbar; | |
+import android.view.Menu; | |
import android.view.MenuInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
@@ -55,8 +57,8 @@ | |
@Override | |
protected void onCreate(@Nullable Bundle savedInstanceState) { | |
getDelegate().installViewFactory(); | |
- super.onCreate(savedInstanceState); | |
getDelegate().onCreate(savedInstanceState); | |
+ super.onCreate(savedInstanceState); | |
} | |
@Override | |
@@ -88,7 +90,8 @@ | |
* {@link android.R.id#home home} menu select action.</p> | |
* | |
* <p>In order to use a Toolbar within the Activity's window content the application | |
- * must not request the window feature {@link android.view.Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p> | |
+ * must not request the window feature | |
+ * {@link android.view.Window#FEATURE_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p> | |
* | |
* @param toolbar Toolbar to set as the Activity's action bar | |
*/ | |
@@ -201,6 +204,7 @@ | |
* | |
* @param mode The new action mode. | |
*/ | |
+ @CallSuper | |
public void onSupportActionModeStarted(ActionMode mode) { | |
} | |
@@ -210,6 +214,7 @@ | |
* | |
* @param mode The action mode that just finished. | |
*/ | |
+ @CallSuper | |
public void onSupportActionModeFinished(ActionMode mode) { | |
} | |
@@ -422,6 +427,28 @@ | |
} | |
/** | |
+ * {@inheritDoc} | |
+ * | |
+ * <p>Please note: AppCompat uses it's own feature id for the action bar: | |
+ * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p> | |
+ */ | |
+ @Override | |
+ public boolean onMenuOpened(int featureId, Menu menu) { | |
+ return super.onMenuOpened(featureId, menu); | |
+ } | |
+ | |
+ /** | |
+ * {@inheritDoc} | |
+ * | |
+ * <p>Please note: AppCompat uses it's own feature id for the action bar: | |
+ * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p> | |
+ */ | |
+ @Override | |
+ public void onPanelClosed(int featureId, Menu menu) { | |
+ super.onPanelClosed(featureId, menu); | |
+ } | |
+ | |
+ /** | |
* @return The {@link AppCompatDelegate} being used by this Activity. | |
*/ | |
public AppCompatDelegate getDelegate() { | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegate.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegate.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegate.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegate.java 2015-07-22 08:36:20.000000000 +0900 | |
@@ -22,8 +22,12 @@ | |
import android.content.res.Configuration; | |
import android.os.Build; | |
import android.os.Bundle; | |
+import android.support.annotation.IntDef; | |
+import android.support.annotation.LayoutRes; | |
import android.support.annotation.NonNull; | |
import android.support.v4.app.FragmentActivity; | |
+import android.support.v4.view.WindowCompat; | |
+import android.support.v7.appcompat.R; | |
import android.support.v7.view.ActionMode; | |
import android.support.v7.widget.Toolbar; | |
import android.util.AttributeSet; | |
@@ -32,6 +36,9 @@ | |
import android.view.ViewGroup; | |
import android.view.Window; | |
+import java.lang.annotation.Retention; | |
+import java.lang.annotation.RetentionPolicy; | |
+ | |
/** | |
* This class represents a delegate which you can use to extend AppCompat's support to any | |
* {@link android.app.Activity}. | |
@@ -69,6 +76,39 @@ | |
static final String TAG = "AppCompatDelegate"; | |
/** | |
+ * Flag for enabling the support Action Bar. | |
+ * | |
+ * <p>This is enabled by default for some devices. The Action Bar replaces the title bar and | |
+ * provides an alternate location for an on-screen menu button on some devices. | |
+ */ | |
+ public static final int FEATURE_SUPPORT_ACTION_BAR = 100 + WindowCompat.FEATURE_ACTION_BAR; | |
+ | |
+ /** | |
+ * Flag for requesting an support Action Bar that overlays window content. | |
+ * Normally an Action Bar will sit in the space above window content, but if this | |
+ * feature is requested along with {@link #FEATURE_SUPPORT_ACTION_BAR} it will be layered over | |
+ * the window content itself. This is useful if you would like your app to have more control | |
+ * over how the Action Bar is displayed, such as letting application content scroll beneath | |
+ * an Action Bar with a transparent background or otherwise displaying a transparent/translucent | |
+ * Action Bar over application content. | |
+ * | |
+ * <p>This mode is especially useful with {@code View.SYSTEM_UI_FLAG_FULLSCREEN}, which allows | |
+ * you to seamlessly hide the action bar in conjunction with other screen decorations. | |
+ * When an ActionBar is in this mode it will adjust the insets provided to | |
+ * {@link View#fitSystemWindows(android.graphics.Rect) View.fitSystemWindows(Rect)} | |
+ * to include the content covered by the action bar, so you can do layout within | |
+ * that space. | |
+ */ | |
+ public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = | |
+ 100 + WindowCompat.FEATURE_ACTION_BAR_OVERLAY; | |
+ | |
+ /** | |
+ * Flag for specifying the behavior of action modes when an Action Bar is not present. | |
+ * If overlay is enabled, the action mode UI will be allowed to cover existing window content. | |
+ */ | |
+ public static final int FEATURE_ACTION_MODE_OVERLAY = WindowCompat.FEATURE_ACTION_MODE_OVERLAY; | |
+ | |
+ /** | |
* Create a {@link android.support.v7.app.AppCompatDelegate} to use with {@code activity}. | |
* | |
* @param callback An optional callback for AppCompat specific events | |
@@ -89,7 +129,9 @@ | |
private static AppCompatDelegate create(Context context, Window window, | |
AppCompatCallback callback) { | |
final int sdk = Build.VERSION.SDK_INT; | |
- if (sdk >= 14) { | |
+ if (sdk >= 23) { | |
+ return new AppCompatDelegateImplV23(context, window, callback); | |
+ } else if (sdk >= 14) { | |
return new AppCompatDelegateImplV14(context, window, callback); | |
} else if (sdk >= 11) { | |
return new AppCompatDelegateImplV11(context, window, callback); | |
@@ -121,7 +163,7 @@ | |
* | |
* <p>In order to use a Toolbar within the Activity's window content the application | |
* must not request the window feature | |
- * {@link android.view.Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p> | |
+ * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p> | |
* | |
* @param toolbar Toolbar to set as the Activity's action bar | |
*/ | |
@@ -166,7 +208,7 @@ | |
/** | |
* Should be called instead of {@link Activity#setContentView(int)}} | |
*/ | |
- public abstract void setContentView(int resId); | |
+ public abstract void setContentView(@LayoutRes int resId); | |
/** | |
* Should be called instead of | |
@@ -214,6 +256,16 @@ | |
public abstract boolean requestWindowFeature(int featureId); | |
/** | |
+ * Query for the availability of a certain feature. | |
+ * | |
+ * <p>This should be called instead of {@link android.view.Window#hasFeature(int)}.</p> | |
+ * | |
+ * @param featureId The feature ID to check | |
+ * @return true if the feature is enabled, false otherwise. | |
+ */ | |
+ public abstract boolean hasWindowFeature(int featureId); | |
+ | |
+ /** | |
* Start an action mode. | |
* | |
* @param callback Callback that will manage lifecycle events for this context mode | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplBase.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplBase.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplBase.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplBase.java 2015-07-22 08:36:20.000000000 +0900 | |
@@ -17,14 +17,11 @@ | |
package android.support.v7.app; | |
import android.app.Activity; | |
-import android.app.Dialog; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.drawable.Drawable; | |
-import android.os.Build; | |
import android.os.Bundle; | |
import android.support.v7.appcompat.R; | |
-import android.support.v7.internal.app.WindowDecorActionBar; | |
import android.support.v7.internal.view.SupportMenuInflater; | |
import android.support.v7.internal.view.WindowCallbackWrapper; | |
import android.support.v7.internal.view.menu.MenuBuilder; | |
@@ -44,8 +41,8 @@ | |
final Window.Callback mAppCompatWindowCallback; | |
final AppCompatCallback mAppCompatCallback; | |
- private ActionBar mActionBar; | |
- private MenuInflater mMenuInflater; | |
+ ActionBar mActionBar; | |
+ MenuInflater mMenuInflater; | |
// true if this activity has an action bar. | |
boolean mHasActionBar; | |
@@ -77,7 +74,7 @@ | |
mWindow.setCallback(mAppCompatWindowCallback); | |
} | |
- abstract ActionBar createSupportActionBar(); | |
+ abstract void initWindowDecorActionBar(); | |
Window.Callback wrapWindowCallback(Window.Callback callback) { | |
return new AppCompatWindowCallbackBase(callback); | |
@@ -87,15 +84,7 @@ | |
public ActionBar getSupportActionBar() { | |
// The Action Bar should be lazily created as hasActionBar | |
// could change after onCreate | |
- if (mHasActionBar) { | |
- if (mActionBar == null) { | |
- mActionBar = createSupportActionBar(); | |
- } | |
- } else { | |
- if (mActionBar instanceof WindowDecorActionBar) { | |
- mActionBar = null; | |
- } | |
- } | |
+ initWindowDecorActionBar(); | |
return mActionBar; | |
} | |
@@ -103,14 +92,13 @@ | |
return mActionBar; | |
} | |
- final void setSupportActionBar(ActionBar actionBar) { | |
- mActionBar = actionBar; | |
- } | |
- | |
@Override | |
public MenuInflater getMenuInflater() { | |
+ // Make sure that action views can get an appropriate theme. | |
if (mMenuInflater == null) { | |
- mMenuInflater = new SupportMenuInflater(getActionBarThemedContext()); | |
+ initWindowDecorActionBar(); | |
+ mMenuInflater = new SupportMenuInflater( | |
+ mActionBar != null ? mActionBar.getThemedContext() : mContext); | |
} | |
return mMenuInflater; | |
} | |
@@ -125,22 +113,24 @@ | |
"You need to use a Theme.AppCompat theme (or descendant) with this activity."); | |
} | |
- if (a.getBoolean(R.styleable.Theme_windowActionBar, false)) { | |
- mHasActionBar = true; | |
+ if (a.getBoolean(R.styleable.Theme_windowNoTitle, false)) { | |
+ requestWindowFeature(Window.FEATURE_NO_TITLE); | |
+ } else if (a.getBoolean(R.styleable.Theme_windowActionBar, false)) { | |
+ // Don't allow an action bar if there is no title. | |
+ requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR); | |
} | |
if (a.getBoolean(R.styleable.Theme_windowActionBarOverlay, false)) { | |
- mOverlayActionBar = true; | |
+ requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY); | |
} | |
if (a.getBoolean(R.styleable.Theme_windowActionModeOverlay, false)) { | |
- mOverlayActionMode = true; | |
+ requestWindowFeature(FEATURE_ACTION_MODE_OVERLAY); | |
} | |
mIsFloating = a.getBoolean(R.styleable.Theme_android_windowIsFloating, false); | |
- mWindowNoTitle = a.getBoolean(R.styleable.Theme_windowNoTitle, false); | |
a.recycle(); | |
} | |
// Methods used to create and respond to options menu | |
- abstract boolean onPanelClosed(int featureId, Menu menu); | |
+ abstract void onPanelClosed(int featureId, Menu menu); | |
abstract boolean onMenuOpened(int featureId, Menu menu); | |
@@ -257,12 +247,14 @@ | |
@Override | |
public boolean dispatchKeyEvent(KeyEvent event) { | |
- if (AppCompatDelegateImplBase.this.dispatchKeyEvent(event)) { | |
- // First, let us attempt to handle it | |
- return true; | |
- } | |
- // If we reach here, let the wrapped Callback attempt to handle it | |
- return super.dispatchKeyEvent(event); | |
+ return AppCompatDelegateImplBase.this.dispatchKeyEvent(event) | |
+ || super.dispatchKeyEvent(event); | |
+ } | |
+ | |
+ @Override | |
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) { | |
+ return super.dispatchKeyShortcutEvent(event) | |
+ || AppCompatDelegateImplBase.this.onKeyShortcut(event.getKeyCode(), event); | |
} | |
@Override | |
@@ -276,6 +268,12 @@ | |
} | |
@Override | |
+ public void onContentChanged() { | |
+ // We purposely do not propagate this call as this is called when we install | |
+ // our sub-decor rather than the user's content | |
+ } | |
+ | |
+ @Override | |
public boolean onPreparePanel(int featureId, View view, Menu menu) { | |
final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null; | |
@@ -304,32 +302,14 @@ | |
@Override | |
public boolean onMenuOpened(int featureId, Menu menu) { | |
- if (AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu)) { | |
- return true; | |
- } | |
- return super.onMenuOpened(featureId, menu); | |
- } | |
- | |
- @Override | |
- public boolean dispatchKeyShortcutEvent(KeyEvent event) { | |
- if (AppCompatDelegateImplBase.this.onKeyShortcut(event.getKeyCode(), event)) { | |
- return true; | |
- } | |
- return super.dispatchKeyShortcutEvent(event); | |
- } | |
- | |
- @Override | |
- public void onContentChanged() { | |
- // We purposely do not propagate this call as this is called when we install | |
- // our sub-decor rather than the user's content | |
+ return super.onMenuOpened(featureId, menu) | |
+ || AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu); | |
} | |
@Override | |
public void onPanelClosed(int featureId, Menu menu) { | |
- if (AppCompatDelegateImplBase.this.onPanelClosed(featureId, menu)) { | |
- return; | |
- } | |
super.onPanelClosed(featureId, menu); | |
+ AppCompatDelegateImplBase.this.onPanelClosed(featureId, menu); | |
} | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV11.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV11.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV11.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV11.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -29,19 +29,8 @@ | |
} | |
View callActivityOnCreateView(View parent, String name, Context context, AttributeSet attrs) { | |
- // First let super have a try, this allows FragmentActivity to inflate any support | |
- // fragments | |
- final View view = super.callActivityOnCreateView(parent, name, context, attrs); | |
- if (view != null) { | |
- return view; | |
- } | |
- | |
- // Now, let the Activity's LayoutInflater.Factory2 method try... | |
- if (mOriginalWindowCallback instanceof LayoutInflater.Factory2) { | |
- return ((LayoutInflater.Factory2) mOriginalWindowCallback) | |
- .onCreateView(parent, name, context, attrs); | |
- } | |
- | |
+ // On Honeycomb+, Activity's private inflater factory will handle calling it's | |
+ // onCreateView(...) | |
return null; | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV14.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV14.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV14.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV14.java 2015-07-22 08:36:20.000000000 +0900 | |
@@ -54,7 +54,7 @@ | |
@Override | |
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { | |
// We wrap in a support action mode on v14+ if enabled | |
- if (mHandleNativeActionModes) { | |
+ if (isHandleNativeActionModesEnabled()) { | |
return startAsSupportActionMode(callback); | |
} | |
// Else, let the call fall through to the wrapped callback | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV23.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV23.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV23.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV23.java 2015-07-22 08:36:20.000000000 +0900 | |
@@ -0,0 +1,60 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License | |
+ */ | |
+ | |
+package android.support.v7.app; | |
+ | |
+import android.content.Context; | |
+import android.view.ActionMode; | |
+import android.view.Window; | |
+ | |
+class AppCompatDelegateImplV23 extends AppCompatDelegateImplV14 { | |
+ | |
+ AppCompatDelegateImplV23(Context context, Window window, AppCompatCallback callback) { | |
+ super(context, window, callback); | |
+ } | |
+ | |
+ @Override | |
+ Window.Callback wrapWindowCallback(Window.Callback callback) { | |
+ // Override the window callback so that we can intercept onWindowStartingActionMode(type) | |
+ // calls | |
+ return new AppCompatWindowCallbackV23(callback); | |
+ } | |
+ | |
+ class AppCompatWindowCallbackV23 extends AppCompatWindowCallbackV14 { | |
+ AppCompatWindowCallbackV23(Window.Callback callback) { | |
+ super(callback); | |
+ } | |
+ | |
+ @Override | |
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) { | |
+ if (isHandleNativeActionModesEnabled()) { | |
+ switch (type) { | |
+ case ActionMode.TYPE_PRIMARY: | |
+ // We only take over if the type is TYPE_PRIMARY | |
+ return startAsSupportActionMode(callback); | |
+ } | |
+ } | |
+ // Else, let the call fall through to the wrapped callback | |
+ return super.onWindowStartingActionMode(callback, type); | |
+ } | |
+ | |
+ @Override | |
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { | |
+ // No-op on API 23+ | |
+ return null; | |
+ } | |
+ } | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV7.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV7.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatDelegateImplV7.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatDelegateImplV7.java 2015-08-04 08:23:06.000000000 +0900 | |
@@ -36,7 +36,11 @@ | |
import android.support.v4.view.OnApplyWindowInsetsListener; | |
import android.support.v4.view.ViewCompat; | |
import android.support.v4.view.ViewConfigurationCompat; | |
+import android.support.v4.view.ViewPropertyAnimatorCompat; | |
+import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; | |
+import android.support.v4.view.WindowCompat; | |
import android.support.v4.view.WindowInsetsCompat; | |
+import android.support.v4.widget.PopupWindowCompat; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.app.AppCompatViewInflater; | |
import android.support.v7.internal.app.ToolbarActionBar; | |
@@ -79,9 +83,6 @@ | |
import android.widget.PopupWindow; | |
import android.widget.TextView; | |
-import static android.support.v4.view.WindowCompat.FEATURE_ACTION_BAR; | |
-import static android.support.v4.view.WindowCompat.FEATURE_ACTION_BAR_OVERLAY; | |
-import static android.support.v4.view.WindowCompat.FEATURE_ACTION_MODE_OVERLAY; | |
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; | |
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; | |
import static android.view.Window.FEATURE_OPTIONS_PANEL; | |
@@ -97,6 +98,7 @@ | |
ActionBarContextView mActionModeView; | |
PopupWindow mActionModePopup; | |
Runnable mShowActionModePopup; | |
+ ViewPropertyAnimatorCompat mFadeAnim = null; | |
// true if we have installed a window sub-decor layout. | |
private boolean mSubDecorInstalled; | |
@@ -122,8 +124,8 @@ | |
if ((mInvalidatePanelMenuFeatures & 1 << FEATURE_OPTIONS_PANEL) != 0) { | |
doInvalidatePanelMenu(FEATURE_OPTIONS_PANEL); | |
} | |
- if ((mInvalidatePanelMenuFeatures & 1 << FEATURE_ACTION_BAR) != 0) { | |
- doInvalidatePanelMenu(FEATURE_ACTION_BAR); | |
+ if ((mInvalidatePanelMenuFeatures & 1 << FEATURE_SUPPORT_ACTION_BAR) != 0) { | |
+ doInvalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR); | |
} | |
mInvalidatePanelMenuPosted = false; | |
mInvalidatePanelMenuFeatures = 0; | |
@@ -167,18 +169,22 @@ | |
} | |
@Override | |
- public ActionBar createSupportActionBar() { | |
+ public void initWindowDecorActionBar() { | |
ensureSubDecor(); | |
- ActionBar ab = null; | |
+ | |
+ if (!mHasActionBar || mActionBar != null) { | |
+ return; | |
+ } | |
+ | |
if (mOriginalWindowCallback instanceof Activity) { | |
- ab = new WindowDecorActionBar((Activity) mOriginalWindowCallback, mOverlayActionBar); | |
+ mActionBar = new WindowDecorActionBar((Activity) mOriginalWindowCallback, | |
+ mOverlayActionBar); | |
} else if (mOriginalWindowCallback instanceof Dialog) { | |
- ab = new WindowDecorActionBar((Dialog) mOriginalWindowCallback); | |
+ mActionBar = new WindowDecorActionBar((Dialog) mOriginalWindowCallback); | |
} | |
- if (ab != null) { | |
- ab.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp); | |
+ if (mActionBar != null) { | |
+ mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp); | |
} | |
- return ab; | |
} | |
@Override | |
@@ -191,13 +197,15 @@ | |
final ActionBar ab = getSupportActionBar(); | |
if (ab instanceof WindowDecorActionBar) { | |
throw new IllegalStateException("This Activity already has an action bar supplied " + | |
- "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " + | |
+ "by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set " + | |
"windowActionBar to false in your theme to use a Toolbar instead."); | |
} | |
+ // Clear out the MenuInflater to make sure that it is valid for the new Action Bar | |
+ mMenuInflater = null; | |
ToolbarActionBar tbab = new ToolbarActionBar(toolbar, ((Activity) mContext).getTitle(), | |
mAppCompatWindowCallback); | |
- setSupportActionBar(tbab); | |
+ mActionBar = tbab; | |
mWindow.setCallback(tbab.getWrappedWindowCallback()); | |
tbab.invalidateOptionsMenu(); | |
} | |
@@ -307,7 +315,7 @@ | |
* Propagate features to DecorContentParent | |
*/ | |
if (mOverlayActionBar) { | |
- mDecorContentParent.initFeature(FEATURE_ACTION_BAR_OVERLAY); | |
+ mDecorContentParent.initFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY); | |
} | |
if (mFeatureProgress) { | |
mDecorContentParent.initFeature(Window.FEATURE_PROGRESS); | |
@@ -361,7 +369,13 @@ | |
if (mSubDecor == null) { | |
throw new IllegalArgumentException( | |
- "AppCompat does not support the current theme features"); | |
+ "AppCompat does not support the current theme features: { " | |
+ + "windowActionBar: " + mHasActionBar | |
+ + ", windowActionBarOverlay: "+ mOverlayActionBar | |
+ + ", android:windowIsFloating: " + mIsFloating | |
+ + ", windowActionModeOverlay: " + mOverlayActionMode | |
+ + ", windowNoTitle: " + mWindowNoTitle | |
+ + " }"); | |
} | |
if (mDecorContentParent == null) { | |
@@ -416,7 +430,7 @@ | |
// would run normally in order to satisfy instance state restoration. | |
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); | |
if (!isDestroyed() && (st == null || st.menu == null)) { | |
- invalidatePanelMenu(FEATURE_ACTION_BAR); | |
+ invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR); | |
} | |
} | |
} | |
@@ -460,12 +474,22 @@ | |
@Override | |
public boolean requestWindowFeature(int featureId) { | |
+ featureId = sanitizeWindowFeatureId(featureId); | |
+ | |
+ if (mWindowNoTitle && featureId == FEATURE_SUPPORT_ACTION_BAR) { | |
+ return false; // Ignore. No title dominates. | |
+ } | |
+ if (mHasActionBar && featureId == Window.FEATURE_NO_TITLE) { | |
+ // Remove the action bar feature if we have no title. No title dominates. | |
+ mHasActionBar = false; | |
+ } | |
+ | |
switch (featureId) { | |
- case FEATURE_ACTION_BAR: | |
+ case FEATURE_SUPPORT_ACTION_BAR: | |
throwFeatureRequestIfSubDecorInstalled(); | |
mHasActionBar = true; | |
return true; | |
- case FEATURE_ACTION_BAR_OVERLAY: | |
+ case FEATURE_SUPPORT_ACTION_BAR_OVERLAY: | |
throwFeatureRequestIfSubDecorInstalled(); | |
mOverlayActionBar = true; | |
return true; | |
@@ -491,6 +515,26 @@ | |
} | |
@Override | |
+ public boolean hasWindowFeature(int featureId) { | |
+ featureId = sanitizeWindowFeatureId(featureId); | |
+ switch (featureId) { | |
+ case FEATURE_SUPPORT_ACTION_BAR: | |
+ return mHasActionBar; | |
+ case FEATURE_SUPPORT_ACTION_BAR_OVERLAY: | |
+ return mOverlayActionBar; | |
+ case FEATURE_ACTION_MODE_OVERLAY: | |
+ return mOverlayActionMode; | |
+ case Window.FEATURE_PROGRESS: | |
+ return mFeatureProgress; | |
+ case Window.FEATURE_INDETERMINATE_PROGRESS: | |
+ return mFeatureIndeterminateProgress; | |
+ case Window.FEATURE_NO_TITLE: | |
+ return mWindowNoTitle; | |
+ } | |
+ return mWindow.hasFeature(featureId); | |
+ } | |
+ | |
+ @Override | |
void onTitleChanged(CharSequence title) { | |
if (mDecorContentParent != null) { | |
mDecorContentParent.setWindowTitle(title); | |
@@ -502,13 +546,12 @@ | |
} | |
@Override | |
- boolean onPanelClosed(final int featureId, Menu menu) { | |
- if (featureId == FEATURE_ACTION_BAR) { | |
+ void onPanelClosed(final int featureId, Menu menu) { | |
+ if (featureId == FEATURE_SUPPORT_ACTION_BAR) { | |
ActionBar ab = getSupportActionBar(); | |
if (ab != null) { | |
ab.dispatchMenuVisibilityChanged(false); | |
} | |
- return true; | |
} else if (featureId == FEATURE_OPTIONS_PANEL) { | |
// Make sure that the options panel is closed. This is mainly used when we're using a | |
// ToolbarActionBar | |
@@ -517,12 +560,11 @@ | |
closePanel(st, false); | |
} | |
} | |
- return false; | |
} | |
@Override | |
boolean onMenuOpened(final int featureId, Menu menu) { | |
- if (featureId == FEATURE_ACTION_BAR) { | |
+ if (featureId == FEATURE_SUPPORT_ACTION_BAR) { | |
ActionBar ab = getSupportActionBar(); | |
if (ab != null) { | |
ab.dispatchMenuVisibilityChanged(true); | |
@@ -587,6 +629,7 @@ | |
@Override | |
ActionMode startSupportActionModeFromWindow(ActionMode.Callback callback) { | |
+ endOnGoingFadeAnimation(); | |
if (mActionMode != null) { | |
mActionMode.finish(); | |
} | |
@@ -626,6 +669,8 @@ | |
mActionModeView = new ActionBarContextView(actionBarContext); | |
mActionModePopup = new PopupWindow(actionBarContext, null, | |
R.attr.actionModePopupWindowStyle); | |
+ PopupWindowCompat.setWindowLayoutType(mActionModePopup, | |
+ WindowManager.LayoutParams.TYPE_APPLICATION); | |
mActionModePopup.setContentView(mActionModeView); | |
mActionModePopup.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); | |
@@ -640,6 +685,22 @@ | |
mActionModePopup.showAtLocation( | |
mActionModeView, | |
Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0); | |
+ endOnGoingFadeAnimation(); | |
+ ViewCompat.setAlpha(mActionModeView, 0f); | |
+ mFadeAnim = ViewCompat.animate(mActionModeView).alpha(1f); | |
+ mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() { | |
+ @Override | |
+ public void onAnimationEnd(View view) { | |
+ ViewCompat.setAlpha(mActionModeView, 1f); | |
+ mFadeAnim.setListener(null); | |
+ mFadeAnim = null; | |
+ } | |
+ | |
+ @Override | |
+ public void onAnimationStart(View view) { | |
+ mActionModeView.setVisibility(View.VISIBLE); | |
+ } | |
+ }); | |
} | |
}; | |
} else { | |
@@ -654,23 +715,37 @@ | |
} | |
if (mActionModeView != null) { | |
+ endOnGoingFadeAnimation(); | |
mActionModeView.killMode(); | |
mode = new StandaloneActionMode(mActionModeView.getContext(), mActionModeView, | |
wrappedCallback, mActionModePopup == null); | |
if (callback.onCreateActionMode(mode, mode.getMenu())) { | |
mode.invalidate(); | |
mActionModeView.initForMode(mode); | |
- mActionModeView.setVisibility(View.VISIBLE); | |
mActionMode = mode; | |
+ ViewCompat.setAlpha(mActionModeView, 0f); | |
+ mFadeAnim = ViewCompat.animate(mActionModeView).alpha(1f); | |
+ mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() { | |
+ @Override | |
+ public void onAnimationEnd(View view) { | |
+ ViewCompat.setAlpha(mActionModeView, 1f); | |
+ mFadeAnim.setListener(null); | |
+ mFadeAnim = null; | |
+ } | |
+ | |
+ @Override | |
+ public void onAnimationStart(View view) { | |
+ mActionModeView.setVisibility(View.VISIBLE); | |
+ mActionModeView.sendAccessibilityEvent( | |
+ AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); | |
+ if (mActionModeView.getParent() != null) { | |
+ ViewCompat.requestApplyInsets((View) mActionModeView.getParent()); | |
+ } | |
+ } | |
+ }); | |
if (mActionModePopup != null) { | |
mWindow.getDecorView().post(mShowActionModePopup); | |
} | |
- mActionModeView.sendAccessibilityEvent( | |
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); | |
- | |
- if (mActionModeView.getParent() != null) { | |
- ViewCompat.requestApplyInsets((View) mActionModeView.getParent()); | |
- } | |
} else { | |
mActionMode = null; | |
} | |
@@ -682,6 +757,12 @@ | |
return mActionMode; | |
} | |
+ private void endOnGoingFadeAnimation() { | |
+ if (mFadeAnim != null) { | |
+ mFadeAnim.cancel(); | |
+ } | |
+ } | |
+ | |
boolean onBackPressed() { | |
// Back cancels action modes first. | |
if (mActionMode != null) { | |
@@ -738,6 +819,13 @@ | |
@Override | |
boolean dispatchKeyEvent(KeyEvent event) { | |
+ if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) { | |
+ // If this is a MENU event, let the Activity have a go. | |
+ if (mOriginalWindowCallback.dispatchKeyEvent(event)) { | |
+ return true; | |
+ } | |
+ } | |
+ | |
final int keyCode = event.getKeyCode(); | |
final int action = event.getAction(); | |
final boolean isDown = action == KeyEvent.ACTION_DOWN; | |
@@ -748,10 +836,8 @@ | |
boolean onKeyUp(int keyCode, KeyEvent event) { | |
switch (keyCode) { | |
case KeyEvent.KEYCODE_MENU: | |
- if (onKeyUpPanel(Window.FEATURE_OPTIONS_PANEL, event)) { | |
- return true; | |
- } | |
- break; | |
+ onKeyUpPanel(Window.FEATURE_OPTIONS_PANEL, event); | |
+ return true; | |
case KeyEvent.KEYCODE_BACK: | |
PanelFeatureState st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false); | |
if (st != null && st.isOpen) { | |
@@ -769,16 +855,17 @@ | |
boolean onKeyDown(int keyCode, KeyEvent event) { | |
switch (keyCode) { | |
case KeyEvent.KEYCODE_MENU: | |
- if (onKeyDownPanel(Window.FEATURE_OPTIONS_PANEL, event)) { | |
- return true; | |
- } | |
+ onKeyDownPanel(Window.FEATURE_OPTIONS_PANEL, event); | |
+ // Break, and let this fall through to the original callback | |
break; | |
} | |
// On API v7-10 we need to manually call onKeyShortcut() as this is not called | |
// from the Activity | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { | |
- return onKeyShortcut(keyCode, event); | |
+ if (onKeyShortcut(keyCode, event)) { | |
+ return true; | |
+ } | |
} | |
return false; | |
} | |
@@ -792,16 +879,9 @@ | |
mAppCompatViewInflater = new AppCompatViewInflater(); | |
} | |
- // We only want the View to inherit it's context if we're running pre-v21 and... | |
- final boolean inheritContext = isPre21 && mSubDecorInstalled && parent != null | |
- // We do not want to inherit context from any decor content | |
- && parent.getId() != android.R.id.content | |
- // We do not want to inherit context if this is the root view in the layout. | |
- // We use parent.isAttachedToWindow() to determine this, which works because | |
- // an inflated layout is only added to the hierarchy AFTER it is completely | |
- // inflated. Thus isAttachedToWindow() will only return true if the parent | |
- // has not been inflated within the outer inflation call. | |
- && !ViewCompat.isAttachedToWindow(parent); | |
+ // We only want the View to inherit it's context if we're running pre-v21 | |
+ final boolean inheritContext = isPre21 && mSubDecorInstalled | |
+ && shouldInheritContext((ViewParent) parent); | |
return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext, | |
isPre21, /* Only read android:theme pre-L (L+ handles this anyway) */ | |
@@ -809,6 +889,30 @@ | |
); | |
} | |
+ private boolean shouldInheritContext(ViewParent parent) { | |
+ if (parent == null) { | |
+ // The initial parent is null so just return false | |
+ return false; | |
+ } | |
+ while (true) { | |
+ if (parent == null) { | |
+ // Bingo. We've hit a view which has a null parent before being terminated from | |
+ // the loop. This is (most probably) because it's the root view in an inflation | |
+ // call, therefore we should inherit. This works as the inflated layout is only | |
+ // added to the hierarchy at the end of the inflate() call. | |
+ return true; | |
+ } else if (parent == mWindowDecor || !(parent instanceof View) | |
+ || ViewCompat.isAttachedToWindow((View) parent)) { | |
+ // We have either hit the window's decor view, a parent which isn't a View | |
+ // (i.e. ViewRootImpl), or an attached view, so we know that the original parent | |
+ // is currently added to the view hierarchy. This means that it has not be | |
+ // inflated in the current inflate() call and we should not inherit the context. | |
+ return false; | |
+ } | |
+ parent = parent.getParent(); | |
+ } | |
+ } | |
+ | |
@Override | |
public void installViewFactory() { | |
LayoutInflater layoutInflater = LayoutInflater.from(mContext); | |
@@ -977,7 +1081,7 @@ | |
// forget it. This is a lingering event that no longer matters. | |
if (st.menu != null && !st.refreshMenuContent && | |
cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) { | |
- cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu); | |
+ cb.onMenuOpened(FEATURE_SUPPORT_ACTION_BAR, st.menu); | |
mDecorContentParent.showOverflowMenu(); | |
} | |
} | |
@@ -985,7 +1089,7 @@ | |
mDecorContentParent.hideOverflowMenu(); | |
if (!isDestroyed()) { | |
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); | |
- cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu); | |
+ cb.onPanelClosed(FEATURE_SUPPORT_ACTION_BAR, st.menu); | |
} | |
} | |
return; | |
@@ -1003,7 +1107,7 @@ | |
Context context = mContext; | |
// If we have an action bar, initialize the menu with the right theme. | |
- if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) && | |
+ if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_SUPPORT_ACTION_BAR) && | |
mDecorContentParent != null) { | |
final TypedValue outValue = new TypedValue(); | |
final Resources.Theme baseTheme = context.getTheme(); | |
@@ -1085,7 +1189,7 @@ | |
} | |
final boolean isActionBarMenu = | |
- (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR); | |
+ (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_SUPPORT_ACTION_BAR); | |
if (isActionBarMenu && mDecorContentParent != null) { | |
// Enforce ordering guarantees around events so that the action bar never | |
@@ -1176,7 +1280,7 @@ | |
mDecorContentParent.dismissPopups(); | |
Window.Callback cb = getWindowCallback(); | |
if (cb != null && !isDestroyed()) { | |
- cb.onPanelClosed(FEATURE_ACTION_BAR, menu); | |
+ cb.onPanelClosed(FEATURE_SUPPORT_ACTION_BAR, menu); | |
} | |
mClosingActionMenu = false; | |
} | |
@@ -1192,23 +1296,19 @@ | |
return; | |
} | |
- final boolean wasOpen = st.isOpen; | |
- | |
final WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); | |
- if (wm != null && wasOpen && st.decorView != null) { | |
+ if (wm != null && st.isOpen && st.decorView != null) { | |
wm.removeView(st.decorView); | |
+ | |
+ if (doCallback) { | |
+ callOnPanelClosed(st.featureId, st, null); | |
+ } | |
} | |
st.isPrepared = false; | |
st.isHandled = false; | |
st.isOpen = false; | |
- if (wasOpen && doCallback) { | |
- // If the panel was open and we should callback, do so. This should be done after | |
- // isOpen is updated to ensure that we do not get into an infinite recursion | |
- callOnPanelClosed(st.featureId, st, null); | |
- } | |
- | |
// This view is no longer shown, so null it out | |
st.shownPanelView = null; | |
@@ -1305,9 +1405,11 @@ | |
if ((panel != null) && (!panel.isOpen)) | |
return; | |
- Window.Callback cb = getWindowCallback(); | |
- if (cb != null) { | |
- cb.onPanelClosed(featureId, menu); | |
+ if (!isDestroyed()) { | |
+ // We need to be careful which callback we dispatch the call to. We can not dispatch | |
+ // this to the Window's callback since that will call back into this method and cause a | |
+ // crash. Instead we need to dispatch down to the original Activity/Dialog/etc. | |
+ mOriginalWindowCallback.onPanelClosed(featureId, menu); | |
} | |
} | |
@@ -1391,7 +1493,7 @@ | |
st.refreshDecorView = true; | |
// Prepare the options panel if we have an action bar | |
- if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL) | |
+ if ((featureId == FEATURE_SUPPORT_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL) | |
&& mDecorContentParent != null) { | |
st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false); | |
if (st != null) { | |
@@ -1484,6 +1586,20 @@ | |
} | |
} | |
+ private int sanitizeWindowFeatureId(int featureId) { | |
+ if (featureId == WindowCompat.FEATURE_ACTION_BAR) { | |
+ Log.i(TAG, "You should now use the AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR" | |
+ + " id when requesting this feature."); | |
+ return FEATURE_SUPPORT_ACTION_BAR; | |
+ } else if (featureId == WindowCompat.FEATURE_ACTION_BAR_OVERLAY) { | |
+ Log.i(TAG, "You should now use the AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR_OVERLAY" | |
+ + " id when requesting this feature."); | |
+ return FEATURE_SUPPORT_ACTION_BAR_OVERLAY; | |
+ } | |
+ // Else we'll just return the original id | |
+ return featureId; | |
+ } | |
+ | |
ViewGroup getSubDecor() { | |
return mSubDecor; | |
} | |
@@ -1514,15 +1630,25 @@ | |
mWrapped.onDestroyActionMode(mode); | |
if (mActionModePopup != null) { | |
mWindow.getDecorView().removeCallbacks(mShowActionModePopup); | |
- mActionModePopup.dismiss(); | |
- } else if (mActionModeView != null) { | |
- mActionModeView.setVisibility(View.GONE); | |
- if (mActionModeView.getParent() != null) { | |
- ViewCompat.requestApplyInsets((View) mActionModeView.getParent()); | |
- } | |
} | |
+ | |
if (mActionModeView != null) { | |
- mActionModeView.removeAllViews(); | |
+ endOnGoingFadeAnimation(); | |
+ mFadeAnim = ViewCompat.animate(mActionModeView).alpha(0f); | |
+ mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() { | |
+ @Override | |
+ public void onAnimationEnd(View view) { | |
+ mActionModeView.setVisibility(View.GONE); | |
+ if (mActionModePopup != null) { | |
+ mActionModePopup.dismiss(); | |
+ } else if (mActionModeView.getParent() instanceof View) { | |
+ ViewCompat.requestApplyInsets((View) mActionModeView.getParent()); | |
+ } | |
+ mActionModeView.removeAllViews(); | |
+ mFadeAnim.setListener(null); | |
+ mFadeAnim = null; | |
+ } | |
+ }); | |
} | |
if (mAppCompatCallback != null) { | |
mAppCompatCallback.onSupportActionModeFinished(mActionMode); | |
@@ -1554,7 +1680,7 @@ | |
if (subMenu == null && mHasActionBar) { | |
Window.Callback cb = getWindowCallback(); | |
if (cb != null && !isDestroyed()) { | |
- cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); | |
+ cb.onMenuOpened(FEATURE_SUPPORT_ACTION_BAR, subMenu); | |
} | |
} | |
return true; | |
@@ -1566,7 +1692,7 @@ | |
public boolean onOpenSubMenu(MenuBuilder subMenu) { | |
Window.Callback cb = getWindowCallback(); | |
if (cb != null) { | |
- cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); | |
+ cb.onMenuOpened(FEATURE_SUPPORT_ACTION_BAR, subMenu); | |
} | |
return true; | |
} | |
@@ -1804,7 +1930,8 @@ | |
@Override | |
public boolean dispatchKeyEvent(KeyEvent event) { | |
- return AppCompatDelegateImplV7.this.dispatchKeyEvent(event); | |
+ return AppCompatDelegateImplV7.this.dispatchKeyEvent(event) | |
+ || super.dispatchKeyEvent(event); | |
} | |
@Override | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/AppCompatDialogFragment.java appcampat-v7-23.0.0/android/support/v7/app/AppCompatDialogFragment.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/AppCompatDialogFragment.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/AppCompatDialogFragment.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -0,0 +1,61 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.app; | |
+ | |
+ | |
+import android.app.Dialog; | |
+import android.os.Bundle; | |
+import android.support.v4.app.DialogFragment; | |
+import android.view.Window; | |
+import android.view.WindowManager; | |
+ | |
+/** | |
+ * A special version of {@link DialogFragment} which uses an {@link AppCompatDialog} in place of a | |
+ * platform-styled dialog. | |
+ * | |
+ * @see DialogFragment | |
+ */ | |
+public class AppCompatDialogFragment extends DialogFragment { | |
+ | |
+ @Override | |
+ public Dialog onCreateDialog(Bundle savedInstanceState) { | |
+ return new AppCompatDialog(getActivity(), getTheme()); | |
+ } | |
+ | |
+ /** @hide */ | |
+ @Override | |
+ public void setupDialog(Dialog dialog, int style) { | |
+ if (dialog instanceof AppCompatDialog) { | |
+ // If the dialog is an AppCompatDialog, we'll handle it | |
+ AppCompatDialog acd = (AppCompatDialog) dialog; | |
+ switch (style) { | |
+ case STYLE_NO_INPUT: | |
+ dialog.getWindow().addFlags( | |
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | | |
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); | |
+ // fall through... | |
+ case STYLE_NO_FRAME: | |
+ case STYLE_NO_TITLE: | |
+ acd.supportRequestWindowFeature(Window.FEATURE_NO_TITLE); | |
+ } | |
+ } else { | |
+ // Else, just let super handle it | |
+ super.setupDialog(dialog, style); | |
+ } | |
+ } | |
+ | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/DrawerArrowDrawable.java appcampat-v7-23.0.0/android/support/v7/app/DrawerArrowDrawable.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/DrawerArrowDrawable.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/DrawerArrowDrawable.java 1970-01-01 09:00:00.000000000 +0900 | |
@@ -1,207 +0,0 @@ | |
-/* | |
- * Copyright (C) 2014 The Android Open Source Project | |
- * | |
- * Licensed under the Apache License, Version 2.0 (the "License"); | |
- * you may not use this file except in compliance with the License. | |
- * You may obtain a copy of the License at | |
- * | |
- * http://www.apache.org/licenses/LICENSE-2.0 | |
- * | |
- * Unless required by applicable law or agreed to in writing, software | |
- * distributed under the License is distributed on an "AS IS" BASIS, | |
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
- * See the License for the specific language governing permissions and | |
- * limitations under the License. | |
- */ | |
-package android.support.v7.app; | |
- | |
- | |
-import android.content.Context; | |
-import android.content.res.TypedArray; | |
-import android.graphics.Canvas; | |
-import android.graphics.Color; | |
-import android.graphics.ColorFilter; | |
-import android.graphics.Paint; | |
-import android.graphics.Path; | |
-import android.graphics.PixelFormat; | |
-import android.graphics.Rect; | |
-import android.graphics.drawable.Drawable; | |
-import android.support.v7.appcompat.R; | |
- | |
-/** | |
- * A drawable that can draw a "Drawer hamburger" menu or an Arrow and animate between them. | |
- */ | |
-abstract class DrawerArrowDrawable extends Drawable { | |
- | |
- private final Paint mPaint = new Paint(); | |
- | |
- // The angle in degress that the arrow head is inclined at. | |
- private static final float ARROW_HEAD_ANGLE = (float) Math.toRadians(45); | |
- private final float mBarThickness; | |
- // The length of top and bottom bars when they merge into an arrow | |
- private final float mTopBottomArrowSize; | |
- // The length of middle bar | |
- private final float mBarSize; | |
- // The length of the middle bar when arrow is shaped | |
- private final float mMiddleArrowSize; | |
- // The space between bars when they are parallel | |
- private final float mBarGap; | |
- // Whether bars should spin or not during progress | |
- private final boolean mSpin; | |
- // Use Path instead of canvas operations so that if color has transparency, overlapping sections | |
- // wont look different | |
- private final Path mPath = new Path(); | |
- // The reported intrinsic size of the drawable. | |
- private final int mSize; | |
- // Whether we should mirror animation when animation is reversed. | |
- private boolean mVerticalMirror = false; | |
- // The interpolated version of the original progress | |
- private float mProgress; | |
- // the amount that overlaps w/ bar size when rotation is max | |
- private float mMaxCutForBarSize; | |
- // The distance of arrow's center from top when horizontal | |
- private float mCenterOffset; | |
- | |
- /** | |
- * @param context used to get the configuration for the drawable from | |
- */ | |
- DrawerArrowDrawable(Context context) { | |
- final TypedArray typedArray = context.getTheme() | |
- .obtainStyledAttributes(null, R.styleable.DrawerArrowToggle, | |
- R.attr.drawerArrowStyle, | |
- R.style.Base_Widget_AppCompat_DrawerArrowToggle); | |
- mPaint.setAntiAlias(true); | |
- mPaint.setColor(typedArray.getColor(R.styleable.DrawerArrowToggle_color, 0)); | |
- mSize = typedArray.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0); | |
- // round this because having this floating may cause bad measurements | |
- mBarSize = Math.round(typedArray.getDimension(R.styleable.DrawerArrowToggle_barSize, 0)); | |
- // round this because having this floating may cause bad measurements | |
- mTopBottomArrowSize = Math.round(typedArray.getDimension( | |
- R.styleable.DrawerArrowToggle_topBottomBarArrowSize, 0)); | |
- mBarThickness = typedArray.getDimension(R.styleable.DrawerArrowToggle_thickness, 0); | |
- // round this because having this floating may cause bad measurements | |
- mBarGap = Math.round(typedArray.getDimension( | |
- R.styleable.DrawerArrowToggle_gapBetweenBars, 0)); | |
- mSpin = typedArray.getBoolean(R.styleable.DrawerArrowToggle_spinBars, true); | |
- mMiddleArrowSize = typedArray | |
- .getDimension(R.styleable.DrawerArrowToggle_middleBarArrowSize, 0); | |
- final int remainingSpace = (int) (mSize - mBarThickness * 3 - mBarGap * 2); | |
- mCenterOffset = (remainingSpace / 4) * 2; //making sure it is a multiple of 2. | |
- mCenterOffset += mBarThickness * 1.5 + mBarGap; | |
- typedArray.recycle(); | |
- | |
- mPaint.setStyle(Paint.Style.STROKE); | |
- mPaint.setStrokeJoin(Paint.Join.MITER); | |
- mPaint.setStrokeCap(Paint.Cap.BUTT); | |
- mPaint.setStrokeWidth(mBarThickness); | |
- | |
- mMaxCutForBarSize = (float) (mBarThickness / 2 * Math.cos(ARROW_HEAD_ANGLE)); | |
- } | |
- | |
- abstract boolean isLayoutRtl(); | |
- | |
- /** | |
- * If set, canvas is flipped when progress reached to end and going back to start. | |
- */ | |
- protected void setVerticalMirror(boolean verticalMirror) { | |
- mVerticalMirror = verticalMirror; | |
- } | |
- | |
- @Override | |
- public void draw(Canvas canvas) { | |
- Rect bounds = getBounds(); | |
- final boolean isRtl = isLayoutRtl(); | |
- // Interpolated widths of arrow bars | |
- final float arrowSize = lerp(mBarSize, mTopBottomArrowSize, mProgress); | |
- final float middleBarSize = lerp(mBarSize, mMiddleArrowSize, mProgress); | |
- // Interpolated size of middle bar | |
- final float middleBarCut = Math.round(lerp(0, mMaxCutForBarSize, mProgress)); | |
- // The rotation of the top and bottom bars (that make the arrow head) | |
- final float rotation = lerp(0, ARROW_HEAD_ANGLE, mProgress); | |
- | |
- // The whole canvas rotates as the transition happens | |
- final float canvasRotate = lerp(isRtl ? 0 : -180, isRtl ? 180 : 0, mProgress); | |
- final float arrowWidth = Math.round(arrowSize * Math.cos(rotation)); | |
- final float arrowHeight = Math.round(arrowSize * Math.sin(rotation)); | |
- | |
- | |
- mPath.rewind(); | |
- final float topBottomBarOffset = lerp(mBarGap + mBarThickness, -mMaxCutForBarSize, | |
- mProgress); | |
- | |
- final float arrowEdge = -middleBarSize / 2; | |
- // draw middle bar | |
- mPath.moveTo(arrowEdge + middleBarCut, 0); | |
- mPath.rLineTo(middleBarSize - middleBarCut * 2, 0); | |
- | |
- // bottom bar | |
- mPath.moveTo(arrowEdge, topBottomBarOffset); | |
- mPath.rLineTo(arrowWidth, arrowHeight); | |
- | |
- // top bar | |
- mPath.moveTo(arrowEdge, -topBottomBarOffset); | |
- mPath.rLineTo(arrowWidth, -arrowHeight); | |
- | |
- mPath.close(); | |
- | |
- canvas.save(); | |
- // Rotate the whole canvas if spinning, if not, rotate it 180 to get | |
- // the arrow pointing the other way for RTL. | |
- canvas.translate(bounds.centerX(), mCenterOffset); | |
- if (mSpin) { | |
- canvas.rotate(canvasRotate * ((mVerticalMirror ^ isRtl) ? -1 : 1)); | |
- } else if (isRtl) { | |
- canvas.rotate(180); | |
- } | |
- canvas.drawPath(mPath, mPaint); | |
- | |
- canvas.restore(); | |
- } | |
- | |
- @Override | |
- public void setAlpha(int i) { | |
- mPaint.setAlpha(i); | |
- } | |
- | |
- // override | |
- public boolean isAutoMirrored() { | |
- // Draws rotated 180 degrees in RTL mode. | |
- return true; | |
- } | |
- | |
- @Override | |
- public void setColorFilter(ColorFilter colorFilter) { | |
- mPaint.setColorFilter(colorFilter); | |
- } | |
- | |
- @Override | |
- public int getIntrinsicHeight() { | |
- return mSize; | |
- } | |
- | |
- @Override | |
- public int getIntrinsicWidth() { | |
- return mSize; | |
- } | |
- | |
- @Override | |
- public int getOpacity() { | |
- return PixelFormat.TRANSLUCENT; | |
- } | |
- | |
- public float getProgress() { | |
- return mProgress; | |
- } | |
- | |
- public void setProgress(float progress) { | |
- mProgress = progress; | |
- invalidateSelf(); | |
- } | |
- | |
- /** | |
- * Linear interpolate between a and b with parameter t. | |
- */ | |
- private static float lerp(float a, float b, float t) { | |
- return a + (b - a) * t; | |
- } | |
-} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/TwilightCalculator.java appcampat-v7-23.0.0/android/support/v7/app/TwilightCalculator.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/TwilightCalculator.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/TwilightCalculator.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -0,0 +1,137 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.app; | |
+ | |
+import android.text.format.DateUtils; | |
+ | |
+/** | |
+ * Imported from frameworks/base/services/core/java/com/android/server/TwilightCalculator.java | |
+ * | |
+ * <p>Calculates the sunrise and sunsets times for a given location.</p> | |
+ */ | |
+class TwilightCalculator { | |
+ | |
+ private static TwilightCalculator sInstance; | |
+ | |
+ static TwilightCalculator getInstance() { | |
+ if (sInstance == null) { | |
+ sInstance = new TwilightCalculator(); | |
+ } | |
+ return sInstance; | |
+ } | |
+ | |
+ /** Value of {@link #state} if it is currently day */ | |
+ public static final int DAY = 0; | |
+ | |
+ /** Value of {@link #state} if it is currently night */ | |
+ public static final int NIGHT = 1; | |
+ | |
+ private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f); | |
+ | |
+ // element for calculating solar transit. | |
+ private static final float J0 = 0.0009f; | |
+ | |
+ // correction for civil twilight | |
+ private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f; | |
+ | |
+ // coefficients for calculating Equation of Center. | |
+ private static final float C1 = 0.0334196f; | |
+ private static final float C2 = 0.000349066f; | |
+ private static final float C3 = 0.000005236f; | |
+ | |
+ private static final float OBLIQUITY = 0.40927971f; | |
+ | |
+ // Java time on Jan 1, 2000 12:00 UTC. | |
+ private static final long UTC_2000 = 946728000000L; | |
+ | |
+ /** | |
+ * Time of sunset (civil twilight) in milliseconds or -1 in the case the day | |
+ * or night never ends. | |
+ */ | |
+ public long sunset; | |
+ | |
+ /** | |
+ * Time of sunrise (civil twilight) in milliseconds or -1 in the case the | |
+ * day or night never ends. | |
+ */ | |
+ public long sunrise; | |
+ | |
+ /** | |
+ * Current state | |
+ */ | |
+ public int state; | |
+ | |
+ /** | |
+ * calculates the civil twilight bases on time and geo-coordinates. | |
+ * | |
+ * @param time time in milliseconds. | |
+ * @param latiude latitude in degrees. | |
+ * @param longitude latitude in degrees. | |
+ */ | |
+ public void calculateTwilight(long time, double latiude, double longitude) { | |
+ final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS; | |
+ | |
+ // mean anomaly | |
+ final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f; | |
+ | |
+ // true anomaly | |
+ final double trueAnomaly = meanAnomaly + C1 * Math.sin(meanAnomaly) + C2 | |
+ * Math.sin(2 * meanAnomaly) + C3 * Math.sin(3 * meanAnomaly); | |
+ | |
+ // ecliptic longitude | |
+ final double solarLng = trueAnomaly + 1.796593063d + Math.PI; | |
+ | |
+ // solar transit in days since 2000 | |
+ final double arcLongitude = -longitude / 360; | |
+ float n = Math.round(daysSince2000 - J0 - arcLongitude); | |
+ double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053d * Math.sin(meanAnomaly) | |
+ + -0.0069d * Math.sin(2 * solarLng); | |
+ | |
+ // declination of sun | |
+ double solarDec = Math.asin(Math.sin(solarLng) * Math.sin(OBLIQUITY)); | |
+ | |
+ final double latRad = latiude * DEGREES_TO_RADIANS; | |
+ | |
+ double cosHourAngle = (Math.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad) | |
+ * Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec)); | |
+ // The day or night never ends for the given date and location, if this value is out of | |
+ // range. | |
+ if (cosHourAngle >= 1) { | |
+ state = NIGHT; | |
+ sunset = -1; | |
+ sunrise = -1; | |
+ return; | |
+ } else if (cosHourAngle <= -1) { | |
+ state = DAY; | |
+ sunset = -1; | |
+ sunrise = -1; | |
+ return; | |
+ } | |
+ | |
+ float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI)); | |
+ | |
+ sunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000; | |
+ sunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000; | |
+ | |
+ if (sunrise < time && sunset > time) { | |
+ state = DAY; | |
+ } else { | |
+ state = NIGHT; | |
+ } | |
+ } | |
+ | |
+} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/app/TwilightManager.java appcampat-v7-23.0.0/android/support/v7/app/TwilightManager.java | |
--- appcampat-v7-22.2.1/android/support/v7/app/TwilightManager.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/app/TwilightManager.java 2015-06-25 19:03:06.000000000 +0900 | |
@@ -0,0 +1,185 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.app; | |
+ | |
+import android.Manifest; | |
+import android.content.Context; | |
+import android.location.Location; | |
+import android.location.LocationManager; | |
+import android.support.annotation.NonNull; | |
+import android.support.v4.content.PermissionChecker; | |
+import android.text.format.DateUtils; | |
+import android.util.Log; | |
+ | |
+import java.util.Calendar; | |
+ | |
+/** | |
+ * Class which managing whether we are in the night or not. | |
+ */ | |
+class TwilightManager { | |
+ | |
+ private static final String TAG = "TwilightManager"; | |
+ | |
+ private static final int SUNRISE = 6; // 6am | |
+ private static final int SUNSET = 22; // 10pm | |
+ | |
+ private static final TwilightState sTwilightState = new TwilightState(); | |
+ | |
+ private final Context mContext; | |
+ private final LocationManager mLocationManager; | |
+ | |
+ TwilightManager(Context context) { | |
+ mContext = context; | |
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); | |
+ } | |
+ | |
+ /** | |
+ * Returns true we are currently in the 'night'. | |
+ * | |
+ * @return true if we are at night, false if the day. | |
+ */ | |
+ boolean isNight() { | |
+ final TwilightState state = sTwilightState; | |
+ | |
+ if (isStateValid(state)) { | |
+ // If the current twilight state is still valid, use it | |
+ return state.isNight; | |
+ } | |
+ | |
+ // Else, we will try and grab the last known location | |
+ final Location location = getLastKnownLocation(); | |
+ if (location != null) { | |
+ updateState(location); | |
+ return state.isNight; | |
+ } | |
+ | |
+ Log.i(TAG, "Could not get last known location. This is probably because the app does not" | |
+ + " have any location permissions. Falling back to hardcoded" | |
+ + " sunrise/sunset values."); | |
+ | |
+ // If we don't have a location, we'll use our hardcoded sunrise/sunset values. | |
+ // These aren't great, but it's better than nothing. | |
+ Calendar calendar = Calendar.getInstance(); | |
+ final int hour = calendar.get(Calendar.HOUR_OF_DAY); | |
+ return hour < SUNRISE || hour >= SUNSET; | |
+ } | |
+ | |
+ private Location getLastKnownLocation() { | |
+ Location coarseLocation = null; | |
+ Location fineLocation = null; | |
+ | |
+ int permission = PermissionChecker.checkSelfPermission(mContext, | |
+ Manifest.permission.ACCESS_FINE_LOCATION); | |
+ if (permission == PermissionChecker.PERMISSION_GRANTED) { | |
+ coarseLocation = getLastKnownLocationForProvider(LocationManager.NETWORK_PROVIDER); | |
+ } | |
+ | |
+ permission = PermissionChecker.checkSelfPermission(mContext, | |
+ Manifest.permission.ACCESS_COARSE_LOCATION); | |
+ if (permission == PermissionChecker.PERMISSION_GRANTED) { | |
+ fineLocation = getLastKnownLocationForProvider(LocationManager.GPS_PROVIDER); | |
+ } | |
+ | |
+ if (coarseLocation != null && fineLocation != null) { | |
+ // If we have both a fine and coarse location, use the latest | |
+ if (fineLocation.getTime() > coarseLocation.getTime()) { | |
+ return fineLocation; | |
+ } else { | |
+ return coarseLocation; | |
+ } | |
+ } else { | |
+ // Else, return the non-null one (if there is one) | |
+ return fineLocation != null ? fineLocation : coarseLocation; | |
+ } | |
+ } | |
+ | |
+ private Location getLastKnownLocationForProvider(String provider) { | |
+ if (mLocationManager != null) { | |
+ try { | |
+ if (mLocationManager.isProviderEnabled(provider)) { | |
+ return mLocationManager.getLastKnownLocation(provider); | |
+ } | |
+ } catch (Exception e) { | |
+ Log.d(TAG, "Failed to get last known location", e); | |
+ } | |
+ } | |
+ return null; | |
+ } | |
+ | |
+ private boolean isStateValid(TwilightState state) { | |
+ return state != null && state.nextUpdate > System.currentTimeMillis(); | |
+ } | |
+ | |
+ private void updateState(@NonNull Location location) { | |
+ final TwilightState state = sTwilightState; | |
+ final long now = System.currentTimeMillis(); | |
+ final TwilightCalculator calculator = TwilightCalculator.getInstance(); | |
+ | |
+ // calculate yesterday's twilight | |
+ calculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS, | |
+ location.getLatitude(), location.getLongitude()); | |
+ final long yesterdaySunset = calculator.sunset; | |
+ | |
+ // calculate today's twilight | |
+ calculator.calculateTwilight(now, location.getLatitude(), location.getLongitude()); | |
+ final boolean isNight = (calculator.state == TwilightCalculator.NIGHT); | |
+ final long todaySunrise = calculator.sunrise; | |
+ final long todaySunset = calculator.sunset; | |
+ | |
+ // calculate tomorrow's twilight | |
+ calculator.calculateTwilight(now + DateUtils.DAY_IN_MILLIS, | |
+ location.getLatitude(), location.getLongitude()); | |
+ final long tomorrowSunrise = calculator.sunrise; | |
+ | |
+ // Set next update | |
+ long nextUpdate = 0; | |
+ if (todaySunrise == -1 || todaySunset == -1) { | |
+ // In the case the day or night never ends the update is scheduled 12 hours later. | |
+ nextUpdate = now + 12 * DateUtils.HOUR_IN_MILLIS; | |
+ } else { | |
+ if (now > todaySunset) { | |
+ nextUpdate += tomorrowSunrise; | |
+ } else if (now > todaySunrise) { | |
+ nextUpdate += todaySunset; | |
+ } else { | |
+ nextUpdate += todaySunrise; | |
+ } | |
+ // add some extra time to be on the safe side. | |
+ nextUpdate += DateUtils.MINUTE_IN_MILLIS; | |
+ } | |
+ | |
+ // Update the twilight state | |
+ state.isNight = isNight; | |
+ state.yesterdaySunset = yesterdaySunset; | |
+ state.todaySunrise = todaySunrise; | |
+ state.todaySunset = todaySunset; | |
+ state.tomorrowSunrise = tomorrowSunrise; | |
+ state.nextUpdate = nextUpdate; | |
+ } | |
+ | |
+ /** | |
+ * Describes whether it is day or night. | |
+ */ | |
+ private static class TwilightState { | |
+ boolean isNight; | |
+ long yesterdaySunset; | |
+ long todaySunrise; | |
+ long todaySunset; | |
+ long tomorrowSunrise; | |
+ long nextUpdate; | |
+ } | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/graphics/drawable/DrawableUtils.java appcampat-v7-23.0.0/android/support/v7/graphics/drawable/DrawableUtils.java | |
--- appcampat-v7-22.2.1/android/support/v7/graphics/drawable/DrawableUtils.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/graphics/drawable/DrawableUtils.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -0,0 +1,40 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.graphics.drawable; | |
+ | |
+import android.graphics.PorterDuff; | |
+import android.os.Build; | |
+ | |
+/** | |
+ * @hide | |
+ */ | |
+public class DrawableUtils { | |
+ | |
+ public static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) { | |
+ switch (value) { | |
+ case 3: return PorterDuff.Mode.SRC_OVER; | |
+ case 5: return PorterDuff.Mode.SRC_IN; | |
+ case 9: return PorterDuff.Mode.SRC_ATOP; | |
+ case 14: return PorterDuff.Mode.MULTIPLY; | |
+ case 15: return PorterDuff.Mode.SCREEN; | |
+ case 16: return Build.VERSION.SDK_INT >= 11 ? PorterDuff.Mode.valueOf("ADD") | |
+ : defaultMode; | |
+ default: return defaultMode; | |
+ } | |
+ } | |
+ | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/graphics/drawable/DrawerArrowDrawable.java appcampat-v7-23.0.0/android/support/v7/graphics/drawable/DrawerArrowDrawable.java | |
--- appcampat-v7-22.2.1/android/support/v7/graphics/drawable/DrawerArrowDrawable.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/graphics/drawable/DrawerArrowDrawable.java 2015-07-26 08:18:46.000000000 +0900 | |
@@ -0,0 +1,455 @@ | |
+/* | |
+ * Copyright (C) 2014 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.graphics.drawable; | |
+ | |
+import android.content.Context; | |
+import android.content.res.TypedArray; | |
+import android.graphics.Canvas; | |
+import android.graphics.ColorFilter; | |
+import android.graphics.Paint; | |
+import android.graphics.Path; | |
+import android.graphics.PixelFormat; | |
+import android.graphics.Rect; | |
+import android.graphics.drawable.Drawable; | |
+import android.support.annotation.ColorInt; | |
+import android.support.annotation.FloatRange; | |
+import android.support.annotation.IntDef; | |
+import android.support.v4.graphics.drawable.DrawableCompat; | |
+import android.support.v4.view.ViewCompat; | |
+import android.support.v7.appcompat.R; | |
+ | |
+import java.lang.annotation.Retention; | |
+import java.lang.annotation.RetentionPolicy; | |
+ | |
+/** | |
+ * A drawable that can draw a "Drawer hamburger" menu or an arrow and animate between them. | |
+ * <p> | |
+ * The progress between the two states is controlled via {@link #setProgress(float)}. | |
+ * </p> | |
+ */ | |
+public class DrawerArrowDrawable extends Drawable { | |
+ | |
+ /** | |
+ * Direction to make the arrow point towards the left. | |
+ * | |
+ * @see #setDirection(int) | |
+ * @see #getDirection() | |
+ */ | |
+ public static final int ARROW_DIRECTION_LEFT = 0; | |
+ | |
+ /** | |
+ * Direction to make the arrow point towards the right. | |
+ * | |
+ * @see #setDirection(int) | |
+ * @see #getDirection() | |
+ */ | |
+ public static final int ARROW_DIRECTION_RIGHT = 1; | |
+ | |
+ /** | |
+ * Direction to make the arrow point towards the start. | |
+ * | |
+ * <p>When used in a view with a {@link ViewCompat#LAYOUT_DIRECTION_RTL RTL} layout direction, | |
+ * this is the same as {@link #ARROW_DIRECTION_RIGHT}, otherwise it is the same as | |
+ * {@link #ARROW_DIRECTION_LEFT}.</p> | |
+ * | |
+ * @see #setDirection(int) | |
+ * @see #getDirection() | |
+ */ | |
+ public static final int ARROW_DIRECTION_START = 2; | |
+ | |
+ /** | |
+ * Direction to make the arrow point to the end. | |
+ * | |
+ * <p>When used in a view with a {@link ViewCompat#LAYOUT_DIRECTION_RTL RTL} layout direction, | |
+ * this is the same as {@link #ARROW_DIRECTION_LEFT}, otherwise it is the same as | |
+ * {@link #ARROW_DIRECTION_RIGHT}.</p> | |
+ * | |
+ * @see #setDirection(int) | |
+ * @see #getDirection() | |
+ */ | |
+ public static final int ARROW_DIRECTION_END = 3; | |
+ | |
+ /** @hide */ | |
+ @IntDef({ARROW_DIRECTION_LEFT, ARROW_DIRECTION_RIGHT, | |
+ ARROW_DIRECTION_START, ARROW_DIRECTION_END}) | |
+ @Retention(RetentionPolicy.SOURCE) | |
+ public @interface ArrowDirection {} | |
+ | |
+ private final Paint mPaint = new Paint(); | |
+ | |
+ // The angle in degress that the arrow head is inclined at. | |
+ private static final float ARROW_HEAD_ANGLE = (float) Math.toRadians(45); | |
+ // The length of top and bottom bars when they merge into an arrow | |
+ private float mArrowHeadLength; | |
+ // The length of middle bar | |
+ private float mBarLength; | |
+ // The length of the middle bar when arrow is shaped | |
+ private float mArrowShaftLength; | |
+ // The space between bars when they are parallel | |
+ private float mBarGap; | |
+ // Whether bars should spin or not during progress | |
+ private boolean mSpin; | |
+ // Use Path instead of canvas operations so that if color has transparency, overlapping sections | |
+ // wont look different | |
+ private final Path mPath = new Path(); | |
+ // The reported intrinsic size of the drawable. | |
+ private final int mSize; | |
+ // Whether we should mirror animation when animation is reversed. | |
+ private boolean mVerticalMirror = false; | |
+ // The interpolated version of the original progress | |
+ private float mProgress; | |
+ // the amount that overlaps w/ bar size when rotation is max | |
+ private float mMaxCutForBarSize; | |
+ // The arrow direction | |
+ private int mDirection = ARROW_DIRECTION_START; | |
+ | |
+ /** | |
+ * @param context used to get the configuration for the drawable from | |
+ */ | |
+ public DrawerArrowDrawable(Context context) { | |
+ mPaint.setStyle(Paint.Style.STROKE); | |
+ mPaint.setStrokeJoin(Paint.Join.MITER); | |
+ mPaint.setStrokeCap(Paint.Cap.BUTT); | |
+ mPaint.setAntiAlias(true); | |
+ | |
+ final TypedArray a = context.getTheme().obtainStyledAttributes(null, | |
+ R.styleable.DrawerArrowToggle, R.attr.drawerArrowStyle, | |
+ R.style.Base_Widget_AppCompat_DrawerArrowToggle); | |
+ | |
+ setColor(a.getColor(R.styleable.DrawerArrowToggle_color, 0)); | |
+ setBarThickness(a.getDimension(R.styleable.DrawerArrowToggle_thickness, 0)); | |
+ setSpinEnabled(a.getBoolean(R.styleable.DrawerArrowToggle_spinBars, true)); | |
+ // round this because having this floating may cause bad measurements | |
+ setGapSize(Math.round(a.getDimension(R.styleable.DrawerArrowToggle_gapBetweenBars, 0))); | |
+ | |
+ mSize = a.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0); | |
+ // round this because having this floating may cause bad measurements | |
+ mBarLength = Math.round(a.getDimension(R.styleable.DrawerArrowToggle_barLength, 0)); | |
+ // round this because having this floating may cause bad measurements | |
+ mArrowHeadLength = Math.round(a.getDimension( | |
+ R.styleable.DrawerArrowToggle_arrowHeadLength, 0)); | |
+ mArrowShaftLength = a.getDimension(R.styleable.DrawerArrowToggle_arrowShaftLength, 0); | |
+ a.recycle(); | |
+ } | |
+ | |
+ /** | |
+ * Sets the length of the arrow head (from tip to edge, perpendicular to the shaft). | |
+ * | |
+ * @param length the length in pixels | |
+ */ | |
+ public void setArrowHeadLength(float length) { | |
+ if (mArrowHeadLength != length) { | |
+ mArrowHeadLength = length; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns the length of the arrow head (from tip to edge, perpendicular to the shaft), | |
+ * in pixels. | |
+ */ | |
+ public float getArrowHeadLength() { | |
+ return mArrowHeadLength; | |
+ } | |
+ | |
+ /** | |
+ * Sets the arrow shaft length. | |
+ * | |
+ * @param length the length in pixels | |
+ */ | |
+ public void setArrowShaftLength(float length) { | |
+ if (mArrowShaftLength != length) { | |
+ mArrowShaftLength = length; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns the arrow shaft length in pixels. | |
+ */ | |
+ public float getArrowShaftLength() { | |
+ return mArrowShaftLength; | |
+ } | |
+ | |
+ /** | |
+ * The length of the bars when they are parallel to each other. | |
+ */ | |
+ public float getBarLength() { | |
+ return mBarLength; | |
+ } | |
+ | |
+ /** | |
+ * Sets the length of the bars when they are parallel to each other. | |
+ * | |
+ * @param length the length in pixels | |
+ */ | |
+ public void setBarLength(float length) { | |
+ if (mBarLength != length) { | |
+ mBarLength = length; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Sets the color of the drawable. | |
+ */ | |
+ public void setColor(@ColorInt int color) { | |
+ if (color != mPaint.getColor()) { | |
+ mPaint.setColor(color); | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns the color of the drawable. | |
+ */ | |
+ @ColorInt | |
+ public int getColor() { | |
+ return mPaint.getColor(); | |
+ } | |
+ | |
+ /** | |
+ * Sets the thickness (stroke size) for the bars. | |
+ * | |
+ * @param width stroke width in pixels | |
+ */ | |
+ public void setBarThickness(float width) { | |
+ if (mPaint.getStrokeWidth() != width) { | |
+ mPaint.setStrokeWidth(width); | |
+ mMaxCutForBarSize = (float) (width / 2 * Math.cos(ARROW_HEAD_ANGLE)); | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns the thickness (stroke width) of the bars. | |
+ */ | |
+ public float getBarThickness() { | |
+ return mPaint.getStrokeWidth(); | |
+ } | |
+ | |
+ /** | |
+ * Returns the max gap between the bars when they are parallel to each other. | |
+ * | |
+ * @see #getGapSize() | |
+ */ | |
+ public float getGapSize() { | |
+ return mBarGap; | |
+ } | |
+ | |
+ /** | |
+ * Sets the max gap between the bars when they are parallel to each other. | |
+ * | |
+ * @param gap the gap in pixels | |
+ * | |
+ * @see #getGapSize() | |
+ */ | |
+ public void setGapSize(float gap) { | |
+ if (gap != mBarGap) { | |
+ mBarGap = gap; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Set the arrow direction. | |
+ */ | |
+ public void setDirection(@ArrowDirection int direction) { | |
+ if (direction != mDirection) { | |
+ mDirection = direction; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns whether the bars should rotate or not during the transition. | |
+ * | |
+ * @see #setSpinEnabled(boolean) | |
+ */ | |
+ public boolean isSpinEnabled() { | |
+ return mSpin; | |
+ } | |
+ | |
+ /** | |
+ * Returns whether the bars should rotate or not during the transition. | |
+ * | |
+ * @param enabled true if the bars should rotate. | |
+ * | |
+ * @see #isSpinEnabled() | |
+ */ | |
+ public void setSpinEnabled(boolean enabled) { | |
+ if (mSpin != enabled) { | |
+ mSpin = enabled; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns the arrow direction. | |
+ */ | |
+ @ArrowDirection | |
+ public int getDirection() { | |
+ return mDirection; | |
+ } | |
+ | |
+ /** | |
+ * If set, canvas is flipped when progress reached to end and going back to start. | |
+ */ | |
+ public void setVerticalMirror(boolean verticalMirror) { | |
+ if (mVerticalMirror != verticalMirror) { | |
+ mVerticalMirror = verticalMirror; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public void draw(Canvas canvas) { | |
+ Rect bounds = getBounds(); | |
+ | |
+ final boolean flipToPointRight; | |
+ switch (mDirection) { | |
+ case ARROW_DIRECTION_LEFT: | |
+ flipToPointRight = false; | |
+ break; | |
+ case ARROW_DIRECTION_RIGHT: | |
+ flipToPointRight = true; | |
+ break; | |
+ case ARROW_DIRECTION_END: | |
+ flipToPointRight = DrawableCompat.getLayoutDirection(this) | |
+ == ViewCompat.LAYOUT_DIRECTION_LTR; | |
+ break; | |
+ case ARROW_DIRECTION_START: | |
+ default: | |
+ flipToPointRight = DrawableCompat.getLayoutDirection(this) | |
+ == ViewCompat.LAYOUT_DIRECTION_RTL; | |
+ break; | |
+ } | |
+ | |
+ // Interpolated widths of arrow bars | |
+ | |
+ float arrowHeadBarLength = (float) Math.sqrt(mArrowHeadLength * mArrowHeadLength * 2); | |
+ arrowHeadBarLength = lerp(mBarLength, arrowHeadBarLength, mProgress); | |
+ final float arrowShaftLength = lerp(mBarLength, mArrowShaftLength, mProgress); | |
+ // Interpolated size of middle bar | |
+ final float arrowShaftCut = Math.round(lerp(0, mMaxCutForBarSize, mProgress)); | |
+ // The rotation of the top and bottom bars (that make the arrow head) | |
+ final float rotation = lerp(0, ARROW_HEAD_ANGLE, mProgress); | |
+ | |
+ // The whole canvas rotates as the transition happens | |
+ final float canvasRotate = lerp(flipToPointRight ? 0 : -180, | |
+ flipToPointRight ? 180 : 0, mProgress); | |
+ | |
+ final float arrowWidth = Math.round(arrowHeadBarLength * Math.cos(rotation)); | |
+ final float arrowHeight = Math.round(arrowHeadBarLength * Math.sin(rotation)); | |
+ | |
+ mPath.rewind(); | |
+ final float topBottomBarOffset = lerp(mBarGap + mPaint.getStrokeWidth(), -mMaxCutForBarSize, | |
+ mProgress); | |
+ | |
+ final float arrowEdge = -arrowShaftLength / 2; | |
+ // draw middle bar | |
+ mPath.moveTo(arrowEdge + arrowShaftCut, 0); | |
+ mPath.rLineTo(arrowShaftLength - arrowShaftCut * 2, 0); | |
+ | |
+ // bottom bar | |
+ mPath.moveTo(arrowEdge, topBottomBarOffset); | |
+ mPath.rLineTo(arrowWidth, arrowHeight); | |
+ | |
+ // top bar | |
+ mPath.moveTo(arrowEdge, -topBottomBarOffset); | |
+ mPath.rLineTo(arrowWidth, -arrowHeight); | |
+ | |
+ mPath.close(); | |
+ | |
+ canvas.save(); | |
+ | |
+ // Rotate the whole canvas if spinning, if not, rotate it 180 to get | |
+ // the arrow pointing the other way for RTL. | |
+ final float barThickness = mPaint.getStrokeWidth(); | |
+ final int remainingSpace = (int) (bounds.height() - barThickness * 3 - mBarGap * 2); | |
+ float yOffset = (remainingSpace / 4) * 2; // making sure it is a multiple of 2. | |
+ yOffset += barThickness * 1.5 + mBarGap; | |
+ | |
+ canvas.translate(bounds.centerX(), yOffset); | |
+ if (mSpin) { | |
+ canvas.rotate(canvasRotate * ((mVerticalMirror ^ flipToPointRight) ? -1 : 1)); | |
+ } else if (flipToPointRight) { | |
+ canvas.rotate(180); | |
+ } | |
+ canvas.drawPath(mPath, mPaint); | |
+ | |
+ canvas.restore(); | |
+ } | |
+ | |
+ @Override | |
+ public void setAlpha(int alpha) { | |
+ if (alpha != mPaint.getAlpha()) { | |
+ mPaint.setAlpha(alpha); | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public void setColorFilter(ColorFilter colorFilter) { | |
+ mPaint.setColorFilter(colorFilter); | |
+ invalidateSelf(); | |
+ } | |
+ | |
+ @Override | |
+ public int getIntrinsicHeight() { | |
+ return mSize; | |
+ } | |
+ | |
+ @Override | |
+ public int getIntrinsicWidth() { | |
+ return mSize; | |
+ } | |
+ | |
+ @Override | |
+ public int getOpacity() { | |
+ return PixelFormat.TRANSLUCENT; | |
+ } | |
+ | |
+ /** | |
+ * Returns the current progress of the arrow. | |
+ */ | |
+ @FloatRange(from = 0.0, to = 1.0) | |
+ public float getProgress() { | |
+ return mProgress; | |
+ } | |
+ | |
+ /** | |
+ * Set the progress of the arrow. | |
+ * | |
+ * <p>A value of {@code 0.0} indicates that the arrow should be drawn in it's starting | |
+ * position. A value of {@code 1.0} indicates that the arrow should be drawn in it's ending | |
+ * position.</p> | |
+ */ | |
+ public void setProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { | |
+ if (mProgress != progress) { | |
+ mProgress = progress; | |
+ invalidateSelf(); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Linear interpolate between a and b with parameter t. | |
+ */ | |
+ private static float lerp(float a, float b, float t) { | |
+ return a + (b - a) * t; | |
+ } | |
+} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/app/NavItemSelectedListener.java appcampat-v7-23.0.0/android/support/v7/internal/app/NavItemSelectedListener.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/app/NavItemSelectedListener.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/app/NavItemSelectedListener.java 2015-06-29 08:17:36.000000000 +0900 | |
@@ -18,8 +18,8 @@ | |
package android.support.v7.internal.app; | |
import android.support.v7.app.ActionBar; | |
-import android.support.v7.internal.widget.AdapterViewCompat; | |
import android.view.View; | |
+import android.widget.AdapterView; | |
/** | |
* Wrapper to adapt the ActionBar.OnNavigationListener in an AdapterView.OnItemSelectedListener | |
@@ -27,7 +27,7 @@ | |
* | |
* @hide | |
*/ | |
-class NavItemSelectedListener implements AdapterViewCompat.OnItemSelectedListener { | |
+class NavItemSelectedListener implements AdapterView.OnItemSelectedListener { | |
private final ActionBar.OnNavigationListener mListener; | |
public NavItemSelectedListener(ActionBar.OnNavigationListener listener) { | |
@@ -35,14 +35,14 @@ | |
} | |
@Override | |
- public void onItemSelected(AdapterViewCompat<?> parent, View view, int position, long id) { | |
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { | |
if (mListener != null) { | |
mListener.onNavigationItemSelected(position, id); | |
} | |
} | |
@Override | |
- public void onNothingSelected(AdapterViewCompat<?> parent) { | |
+ public void onNothingSelected(AdapterView<?> parent) { | |
// Do nothing | |
} | |
} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/app/ToolbarActionBar.java appcampat-v7-23.0.0/android/support/v7/internal/app/ToolbarActionBar.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/app/ToolbarActionBar.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/app/ToolbarActionBar.java 2015-07-29 15:00:26.000000000 +0900 | |
@@ -22,8 +22,8 @@ | |
import android.graphics.drawable.Drawable; | |
import android.support.annotation.Nullable; | |
import android.support.v4.view.ViewCompat; | |
-import android.support.v4.view.WindowCompat; | |
import android.support.v7.app.ActionBar; | |
+import android.support.v7.app.AppCompatDelegate; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.view.WindowCallbackWrapper; | |
import android.support.v7.internal.view.menu.ListMenuPresenter; | |
@@ -34,6 +34,7 @@ | |
import android.support.v7.widget.Toolbar; | |
import android.util.TypedValue; | |
import android.view.ContextThemeWrapper; | |
+import android.view.KeyCharacterMap; | |
import android.view.KeyEvent; | |
import android.view.LayoutInflater; | |
import android.view.Menu; | |
@@ -92,7 +93,9 @@ | |
@Override | |
public void setCustomView(View view, LayoutParams layoutParams) { | |
- view.setLayoutParams(layoutParams); | |
+ if (view != null) { | |
+ view.setLayoutParams(layoutParams); | |
+ } | |
mDecorToolbar.setCustomView(view); | |
} | |
@@ -464,7 +467,16 @@ | |
@Override | |
public boolean onKeyShortcut(int keyCode, KeyEvent ev) { | |
Menu menu = getMenu(); | |
- return menu != null ? menu.performShortcut(keyCode, ev, 0) : false; | |
+ if (menu != null) { | |
+ final KeyCharacterMap kmap = KeyCharacterMap.load( | |
+ ev != null ? ev.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD); | |
+ menu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC); | |
+ menu.performShortcut(keyCode, ev, 0); | |
+ } | |
+ // This action bar always returns true for handling keyboard shortcuts. | |
+ // This will block the window from preparing a temporary panel to handle | |
+ // keyboard shortcuts. | |
+ return true; | |
} | |
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { | |
@@ -577,7 +589,7 @@ | |
@Override | |
public boolean onOpenSubMenu(MenuBuilder subMenu) { | |
if (mWindowCallback != null) { | |
- mWindowCallback.onMenuOpened(WindowCompat.FEATURE_ACTION_BAR, subMenu); | |
+ mWindowCallback.onMenuOpened(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, subMenu); | |
return true; | |
} | |
return false; | |
@@ -592,7 +604,7 @@ | |
mClosingActionMenu = true; | |
mDecorToolbar.dismissPopupMenus(); | |
if (mWindowCallback != null) { | |
- mWindowCallback.onPanelClosed(WindowCompat.FEATURE_ACTION_BAR, menu); | |
+ mWindowCallback.onPanelClosed(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, menu); | |
} | |
mClosingActionMenu = false; | |
} | |
@@ -626,10 +638,10 @@ | |
public void onMenuModeChange(MenuBuilder menu) { | |
if (mWindowCallback != null) { | |
if (mDecorToolbar.isOverflowMenuShowing()) { | |
- mWindowCallback.onPanelClosed(WindowCompat.FEATURE_ACTION_BAR, menu); | |
+ mWindowCallback.onPanelClosed(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, menu); | |
} else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, | |
null, menu)) { | |
- mWindowCallback.onMenuOpened(WindowCompat.FEATURE_ACTION_BAR, menu); | |
+ mWindowCallback.onMenuOpened(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, menu); | |
} | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/app/WindowDecorActionBar.java appcampat-v7-23.0.0/android/support/v7/internal/app/WindowDecorActionBar.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/app/WindowDecorActionBar.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/app/WindowDecorActionBar.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -34,8 +34,8 @@ | |
import android.support.v7.app.ActionBar; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.view.ActionBarPolicy; | |
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet; | |
import android.support.v7.internal.view.SupportMenuInflater; | |
+import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet; | |
import android.support.v7.internal.view.menu.MenuBuilder; | |
import android.support.v7.internal.view.menu.MenuPopupHelper; | |
import android.support.v7.internal.view.menu.SubMenuBuilder; | |
@@ -43,8 +43,8 @@ | |
import android.support.v7.internal.widget.ActionBarContextView; | |
import android.support.v7.internal.widget.ActionBarOverlayLayout; | |
import android.support.v7.internal.widget.DecorToolbar; | |
-import android.support.v7.internal.widget.TintManager; | |
import android.support.v7.internal.widget.ScrollingTabContainerView; | |
+import android.support.v7.internal.widget.TintManager; | |
import android.support.v7.view.ActionMode; | |
import android.support.v7.widget.Toolbar; | |
import android.util.TypedValue; | |
@@ -57,7 +57,10 @@ | |
import android.view.ViewParent; | |
import android.view.Window; | |
import android.view.accessibility.AccessibilityEvent; | |
+import android.view.animation.AccelerateInterpolator; | |
import android.view.animation.AnimationUtils; | |
+import android.view.animation.DecelerateInterpolator; | |
+import android.view.animation.Interpolator; | |
import android.widget.SpinnerAdapter; | |
import java.lang.ref.WeakReference; | |
@@ -66,9 +69,6 @@ | |
/** | |
* WindowDecorActionBar is the ActionBar implementation used | |
* by devices of all screen sizes as part of the window decor layout. | |
- * If it detects a compatible decor, it will split contextual modes | |
- * across both the ActionBarView at the top of the screen and | |
- * a horizontal LinearLayout at the bottom which is normally hidden. | |
* | |
* @hide | |
*/ | |
@@ -76,6 +76,9 @@ | |
ActionBarOverlayLayout.ActionBarVisibilityCallback { | |
private static final String TAG = "WindowDecorActionBar"; | |
+ private static final Interpolator sHideInterpolator = new AccelerateInterpolator(); | |
+ private static final Interpolator sShowInterpolator = new DecelerateInterpolator(); | |
+ | |
/** | |
* Only allow show/hide animations on ICS+, as that is what ViewPropertyAnimatorCompat supports | |
*/ | |
@@ -90,7 +93,6 @@ | |
private ActionBarContainer mContainerView; | |
private DecorToolbar mDecorToolbar; | |
private ActionBarContextView mContextView; | |
- private ActionBarContainer mSplitView; | |
private View mContentView; | |
private ScrollingTabContainerView mTabScrollView; | |
@@ -109,12 +111,12 @@ | |
private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = | |
new ArrayList<OnMenuVisibilityListener>(); | |
- private static final int CONTEXT_DISPLAY_NORMAL = 0; | |
- private static final int CONTEXT_DISPLAY_SPLIT = 1; | |
- | |
private static final int INVALID_POSITION = -1; | |
- private int mContextDisplayMode; | |
+ // The fade duration for toolbar and action bar when entering/exiting action mode. | |
+ private static final long FADE_OUT_DURATION_MS = 100; | |
+ private static final long FADE_IN_DURATION_MS = 200; | |
+ | |
private boolean mHasEmbeddedTabs; | |
private int mCurWindowVisibility = View.VISIBLE; | |
@@ -139,9 +141,6 @@ | |
ViewCompat.setTranslationY(mContentView, 0f); | |
ViewCompat.setTranslationY(mContainerView, 0f); | |
} | |
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { | |
- mSplitView.setVisibility(View.GONE); | |
- } | |
mContainerView.setVisibility(View.GONE); | |
mContainerView.setTransitioning(false); | |
mCurrentShowAnim = null; | |
@@ -204,16 +203,12 @@ | |
mContainerView = (ActionBarContainer) decor.findViewById( | |
R.id.action_bar_container); | |
- mSplitView = (ActionBarContainer) decor.findViewById(R.id.split_action_bar); | |
- | |
if (mDecorToolbar == null || mContextView == null || mContainerView == null) { | |
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + | |
"with a compatible window decor layout"); | |
} | |
mContext = mDecorToolbar.getContext(); | |
- mContextDisplayMode = mDecorToolbar.isSplit() ? | |
- CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; | |
// This was initially read from the action bar style | |
final int current = mDecorToolbar.getDisplayOptions(); | |
@@ -253,9 +248,6 @@ | |
@Override | |
public void setElevation(float elevation) { | |
ViewCompat.setElevation(mContainerView, elevation); | |
- if (mSplitView != null) { | |
- ViewCompat.setElevation(mSplitView, elevation); | |
- } | |
} | |
@Override | |
@@ -474,9 +466,7 @@ | |
} | |
public void setSplitBackgroundDrawable(Drawable d) { | |
- if (mSplitView != null) { | |
- mSplitView.setSplitBackground(d); | |
- } | |
+ // no-op. We don't support split action bars | |
} | |
public View getCustomView() { | |
@@ -511,15 +501,6 @@ | |
mode.invalidate(); | |
mContextView.initForMode(mode); | |
animateToMode(true); | |
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { | |
- // TODO animate this | |
- if (mSplitView.getVisibility() != View.VISIBLE) { | |
- mSplitView.setVisibility(View.VISIBLE); | |
- if (mOverlayLayout != null) { | |
- ViewCompat.requestApplyInsets(mOverlayLayout); | |
- } | |
- } | |
- } | |
mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); | |
mActionMode = mode; | |
return mode; | |
@@ -793,13 +774,7 @@ | |
ViewCompat.setTranslationY(mContentView, startingY); | |
anim.play(ViewCompat.animate(mContentView).translationY(0f)); | |
} | |
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { | |
- ViewCompat.setTranslationY(mSplitView, mSplitView.getHeight()); | |
- mSplitView.setVisibility(View.VISIBLE); | |
- anim.play(ViewCompat.animate(mSplitView).translationY(0f)); | |
- } | |
- anim.setInterpolator(AnimationUtils.loadInterpolator(mContext, | |
- android.R.anim.decelerate_interpolator)); | |
+ anim.setInterpolator(sShowInterpolator); | |
anim.setDuration(250); | |
// If this is being shown from the system, add a small delay. | |
// This is because we will also be animating in the status bar, | |
@@ -817,11 +792,6 @@ | |
if (mContentAnimations && mContentView != null) { | |
ViewCompat.setTranslationY(mContentView, 0); | |
} | |
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { | |
- ViewCompat.setAlpha(mSplitView, 1f); | |
- ViewCompat.setTranslationY(mSplitView, 0); | |
- mSplitView.setVisibility(View.VISIBLE); | |
- } | |
mShowListener.onAnimationEnd(null); | |
} | |
if (mOverlayLayout != null) { | |
@@ -851,12 +821,7 @@ | |
if (mContentAnimations && mContentView != null) { | |
anim.play(ViewCompat.animate(mContentView).translationY(endingY)); | |
} | |
- if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) { | |
- ViewCompat.setAlpha(mSplitView, 1f); | |
- anim.play(ViewCompat.animate(mSplitView).translationY(mSplitView.getHeight())); | |
- } | |
- anim.setInterpolator(AnimationUtils.loadInterpolator(mContext, | |
- android.R.anim.accelerate_interpolator)); | |
+ anim.setInterpolator(sHideInterpolator); | |
anim.setDuration(250); | |
anim.setListener(mHideListener); | |
mCurrentShowAnim = anim; | |
@@ -879,8 +844,21 @@ | |
hideForActionMode(); | |
} | |
- mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE); | |
- mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE); | |
+ ViewPropertyAnimatorCompat fadeIn, fadeOut; | |
+ if (toActionMode) { | |
+ fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE, | |
+ FADE_OUT_DURATION_MS); | |
+ fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE, | |
+ FADE_IN_DURATION_MS); | |
+ } else { | |
+ fadeIn = mDecorToolbar.setupAnimatorToVisibility(View.VISIBLE, | |
+ FADE_IN_DURATION_MS); | |
+ fadeOut = mContextView.setupAnimatorToVisibility(View.GONE, | |
+ FADE_OUT_DURATION_MS); | |
+ } | |
+ ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet(); | |
+ set.playSequentially(fadeOut, fadeIn); | |
+ set.start(); | |
// mTabScrollView's visibility is not affected by action mode. | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/ContextThemeWrapper.java appcampat-v7-23.0.0/android/support/v7/internal/view/ContextThemeWrapper.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/ContextThemeWrapper.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/ContextThemeWrapper.java 2015-06-29 08:17:36.000000000 +0900 | |
@@ -19,6 +19,7 @@ | |
import android.content.Context; | |
import android.content.ContextWrapper; | |
import android.content.res.Resources; | |
+import android.support.annotation.StyleRes; | |
import android.support.v7.appcompat.R; | |
import android.view.LayoutInflater; | |
@@ -33,15 +34,22 @@ | |
private Resources.Theme mTheme; | |
private LayoutInflater mInflater; | |
- public ContextThemeWrapper(Context base, int themeres) { | |
+ public ContextThemeWrapper(Context base, @StyleRes int themeResId) { | |
super(base); | |
- mThemeResource = themeres; | |
+ mThemeResource = themeResId; | |
+ } | |
+ | |
+ public ContextThemeWrapper(Context base, Resources.Theme theme) { | |
+ super(base); | |
+ mTheme = theme; | |
} | |
@Override | |
public void setTheme(int resid) { | |
- mThemeResource = resid; | |
- initializeTheme(); | |
+ if (mThemeResource != resid) { | |
+ mThemeResource = resid; | |
+ initializeTheme(); | |
+ } | |
} | |
public int getThemeResId() { | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/SupportMenuInflater.java appcampat-v7-23.0.0/android/support/v7/internal/view/SupportMenuInflater.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/SupportMenuInflater.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/SupportMenuInflater.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -496,6 +496,7 @@ | |
try { | |
Class<?> clazz = mContext.getClassLoader().loadClass(className); | |
Constructor<?> constructor = clazz.getConstructor(constructorSignature); | |
+ constructor.setAccessible(true); | |
return (T) constructor.newInstance(arguments); | |
} catch (Exception e) { | |
Log.w(LOG_TAG, "Cannot instantiate class: " + className, e); | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java appcampat-v7-23.0.0/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -51,6 +51,14 @@ | |
return this; | |
} | |
+ public ViewPropertyAnimatorCompatSet playSequentially(ViewPropertyAnimatorCompat anim1, | |
+ ViewPropertyAnimatorCompat anim2) { | |
+ mAnimators.add(anim1); | |
+ anim2.setStartDelay(anim1.getDuration()); | |
+ mAnimators.add(anim2); | |
+ return this; | |
+ } | |
+ | |
public void start() { | |
if (mIsStarted) return; | |
for (ViewPropertyAnimatorCompat animator : mAnimators) { | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/WindowCallbackWrapper.java appcampat-v7-23.0.0/android/support/v7/internal/view/WindowCallbackWrapper.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/WindowCallbackWrapper.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/WindowCallbackWrapper.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -21,6 +21,7 @@ | |
import android.view.Menu; | |
import android.view.MenuItem; | |
import android.view.MotionEvent; | |
+import android.view.SearchEvent; | |
import android.view.View; | |
import android.view.Window; | |
import android.view.WindowManager; | |
@@ -130,6 +131,11 @@ | |
} | |
@Override | |
+ public boolean onSearchRequested(SearchEvent searchEvent) { | |
+ return mWrapped.onSearchRequested(searchEvent); | |
+ } | |
+ | |
+ @Override | |
public boolean onSearchRequested() { | |
return mWrapped.onSearchRequested(); | |
} | |
@@ -140,6 +146,11 @@ | |
} | |
@Override | |
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) { | |
+ return mWrapped.onWindowStartingActionMode(callback, type); | |
+ } | |
+ | |
+ @Override | |
public void onActionModeStarted(ActionMode mode) { | |
mWrapped.onActionModeStarted(mode); | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/menu/ActionMenuItemView.java appcampat-v7-23.0.0/android/support/v7/internal/view/menu/ActionMenuItemView.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/menu/ActionMenuItemView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/menu/ActionMenuItemView.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -250,7 +250,8 @@ | |
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 | GravityCompat.END, referenceX, height); | |
+ cheatSheet.setGravity(Gravity.TOP | GravityCompat.END, referenceX, | |
+ screenPos[1] + height - displayFrame.top); | |
} else { | |
// Show along the bottom center | |
cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height); | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/menu/MenuBuilder.java appcampat-v7-23.0.0/android/support/v7/internal/view/menu/MenuBuilder.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/menu/MenuBuilder.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/menu/MenuBuilder.java 2015-06-29 08:17:36.000000000 +0900 | |
@@ -429,7 +429,7 @@ | |
/** | |
* Adds an item to the menu. The other add methods funnel to this. | |
*/ | |
- private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) { | |
+ protected MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) { | |
final int ordering = getOrdering(categoryOrder); | |
final MenuItemImpl item = createNewMenuItem(group, id, categoryOrder, ordering, title, | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/menu/MenuItemImpl.java appcampat-v7-23.0.0/android/support/v7/internal/view/menu/MenuItemImpl.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/menu/MenuItemImpl.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/menu/MenuItemImpl.java 2015-07-02 08:14:40.000000000 +0900 | |
@@ -341,7 +341,7 @@ | |
return mSubMenu != null; | |
} | |
- void setSubMenu(SubMenuBuilder subMenu) { | |
+ public void setSubMenu(SubMenuBuilder subMenu) { | |
mSubMenu = subMenu; | |
subMenu.setHeaderTitle(getTitle()); | |
@@ -654,7 +654,7 @@ | |
@Override | |
public SupportMenuItem setSupportActionProvider(ActionProvider actionProvider) { | |
if (mActionProvider != null) { | |
- mActionProvider.setVisibilityListener(null); | |
+ mActionProvider.reset(); | |
} | |
mActionView = null; | |
mActionProvider = actionProvider; | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/view/menu/MenuPopupHelper.java appcampat-v7-23.0.0/android/support/v7/internal/view/menu/MenuPopupHelper.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/view/menu/MenuPopupHelper.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/view/menu/MenuPopupHelper.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -121,6 +121,10 @@ | |
mDropDownGravity = gravity; | |
} | |
+ public int getGravity() { | |
+ return mDropDownGravity; | |
+ } | |
+ | |
public void show() { | |
if (!tryShow()) { | |
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/AbsActionBarView.java appcampat-v7-23.0.0/android/support/v7/internal/widget/AbsActionBarView.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/AbsActionBarView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/AbsActionBarView.java 2015-07-29 15:00:26.000000000 +0900 | |
@@ -13,30 +13,28 @@ | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
+ | |
package android.support.v7.internal.widget; | |
import android.content.Context; | |
import android.content.res.Configuration; | |
import android.content.res.TypedArray; | |
import android.os.Build; | |
+import android.support.v4.view.MotionEventCompat; | |
import android.support.v4.view.ViewCompat; | |
import android.support.v4.view.ViewPropertyAnimatorCompat; | |
import android.support.v4.view.ViewPropertyAnimatorListener; | |
import android.support.v7.appcompat.R; | |
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet; | |
import android.support.v7.widget.ActionMenuPresenter; | |
import android.support.v7.widget.ActionMenuView; | |
import android.util.AttributeSet; | |
import android.util.TypedValue; | |
import android.view.ContextThemeWrapper; | |
+import android.view.MotionEvent; | |
import android.view.View; | |
import android.view.ViewGroup; | |
-import android.view.animation.DecelerateInterpolator; | |
-import android.view.animation.Interpolator; | |
abstract class AbsActionBarView extends ViewGroup { | |
- private static final Interpolator sAlphaInterpolator = new DecelerateInterpolator(); | |
- | |
private static final int FADE_DURATION = 200; | |
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener(); | |
@@ -46,13 +44,13 @@ | |
protected ActionMenuView mMenuView; | |
protected ActionMenuPresenter mActionMenuPresenter; | |
- protected ViewGroup mSplitView; | |
- protected boolean mSplitActionBar; | |
- protected boolean mSplitWhenNarrow; | |
protected int mContentHeight; | |
protected ViewPropertyAnimatorCompat mVisibilityAnim; | |
+ private boolean mEatingTouch; | |
+ private boolean mEatingHover; | |
+ | |
AbsActionBarView(Context context) { | |
this(context, null); | |
} | |
@@ -91,20 +89,55 @@ | |
} | |
} | |
- /** | |
- * Sets whether the bar should be split right now, no questions asked. | |
- * @param split true if the bar should split | |
- */ | |
- public void setSplitToolbar(boolean split) { | |
- mSplitActionBar = split; | |
+ @Override | |
+ public boolean onTouchEvent(MotionEvent ev) { | |
+ // ActionBarViews always eat touch events, but should still respect the touch event dispatch | |
+ // contract. If the normal View implementation doesn't want the events, we'll just silently | |
+ // eat the rest of the gesture without reporting the events to the default implementation | |
+ // since that's what it expects. | |
+ | |
+ final int action = MotionEventCompat.getActionMasked(ev); | |
+ if (action == MotionEvent.ACTION_DOWN) { | |
+ mEatingTouch = false; | |
+ } | |
+ | |
+ if (!mEatingTouch) { | |
+ final boolean handled = super.onTouchEvent(ev); | |
+ if (action == MotionEvent.ACTION_DOWN && !handled) { | |
+ mEatingTouch = true; | |
+ } | |
+ } | |
+ | |
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { | |
+ mEatingTouch = false; | |
+ } | |
+ | |
+ return true; | |
} | |
- /** | |
- * 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; | |
+ @Override | |
+ public boolean onHoverEvent(MotionEvent ev) { | |
+ // Same deal as onTouchEvent() above. Eat all hover events, but still | |
+ // respect the touch event dispatch contract. | |
+ | |
+ final int action = MotionEventCompat.getActionMasked(ev); | |
+ if (action == MotionEventCompat.ACTION_HOVER_ENTER) { | |
+ mEatingHover = false; | |
+ } | |
+ | |
+ if (!mEatingHover) { | |
+ final boolean handled = super.onHoverEvent(ev); | |
+ if (action == MotionEventCompat.ACTION_HOVER_ENTER && !handled) { | |
+ mEatingHover = true; | |
+ } | |
+ } | |
+ | |
+ if (action == MotionEventCompat.ACTION_HOVER_EXIT | |
+ || action == MotionEvent.ACTION_CANCEL) { | |
+ mEatingHover = false; | |
+ } | |
+ | |
+ return true; | |
} | |
public void setContentHeight(int height) { | |
@@ -116,10 +149,6 @@ | |
return mContentHeight; | |
} | |
- public void setSplitView(ViewGroup splitView) { | |
- mSplitView = splitView; | |
- } | |
- | |
/** | |
* @return Current visibility or if animating, the visibility being animated to. | |
*/ | |
@@ -130,46 +159,39 @@ | |
return getVisibility(); | |
} | |
- public void animateToVisibility(int visibility) { | |
+ public ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration) { | |
if (mVisibilityAnim != null) { | |
mVisibilityAnim.cancel(); | |
} | |
+ | |
if (visibility == VISIBLE) { | |
if (getVisibility() != VISIBLE) { | |
ViewCompat.setAlpha(this, 0f); | |
- if (mSplitView != null && mMenuView != null) { | |
- ViewCompat.setAlpha(mMenuView, 0f); | |
- } | |
} | |
ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f); | |
- anim.setDuration(FADE_DURATION); | |
- anim.setInterpolator(sAlphaInterpolator); | |
- if (mSplitView != null && mMenuView != null) { | |
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet(); | |
- ViewPropertyAnimatorCompat splitAnim = ViewCompat.animate(mMenuView).alpha(1f); | |
- splitAnim.setDuration(FADE_DURATION); | |
- set.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); | |
- set.play(anim).play(splitAnim); | |
- set.start(); | |
- } else { | |
- anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); | |
- anim.start(); | |
- } | |
+ anim.setDuration(duration); | |
+ anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); | |
+ return anim; | |
} else { | |
ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(0f); | |
- anim.setDuration(FADE_DURATION); | |
- anim.setInterpolator(sAlphaInterpolator); | |
- if (mSplitView != null && mMenuView != null) { | |
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet(); | |
- ViewPropertyAnimatorCompat splitAnim = ViewCompat.animate(mMenuView).alpha(0f); | |
- splitAnim.setDuration(FADE_DURATION); | |
- set.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); | |
- set.play(anim).play(splitAnim); | |
- set.start(); | |
- } else { | |
- anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); | |
- anim.start(); | |
+ anim.setDuration(duration); | |
+ anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); | |
+ return anim; | |
+ } | |
+ } | |
+ | |
+ public void animateToVisibility(int visibility) { | |
+ ViewPropertyAnimatorCompat anim = setupAnimatorToVisibility(visibility, FADE_DURATION); | |
+ anim.start(); | |
+ } | |
+ | |
+ @Override | |
+ public void setVisibility(int visibility) { | |
+ if (visibility != getVisibility()) { | |
+ if (mVisibilityAnim != null) { | |
+ mVisibilityAnim.cancel(); | |
} | |
+ super.setVisibility(visibility); | |
} | |
} | |
@@ -265,7 +287,7 @@ | |
@Override | |
public void onAnimationStart(View view) { | |
- setVisibility(VISIBLE); | |
+ AbsActionBarView.super.setVisibility(VISIBLE); | |
mCanceled = false; | |
} | |
@@ -274,10 +296,7 @@ | |
if (mCanceled) return; | |
mVisibilityAnim = null; | |
- setVisibility(mFinalVisibility); | |
- if (mSplitView != null && mMenuView != null) { | |
- mMenuView.setVisibility(mFinalVisibility); | |
- } | |
+ AbsActionBarView.super.setVisibility(mFinalVisibility); | |
} | |
@Override | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/AbsSpinnerCompat.java appcampat-v7-23.0.0/android/support/v7/internal/widget/AbsSpinnerCompat.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/AbsSpinnerCompat.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/AbsSpinnerCompat.java 1970-01-01 09:00:00.000000000 +0900 | |
@@ -1,451 +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 android.support.v7.internal.widget; | |
- | |
-import android.content.Context; | |
-import android.database.DataSetObserver; | |
-import android.graphics.Rect; | |
-import android.os.Parcel; | |
-import android.os.Parcelable; | |
-import android.support.v4.view.ViewCompat; | |
-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. | |
- */ | |
-abstract class AbsSpinnerCompat extends AdapterViewCompat<SpinnerAdapter> { | |
- SpinnerAdapter mAdapter; | |
- | |
- int mHeightMeasureSpec; | |
- int mWidthMeasureSpec; | |
- | |
- 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; | |
- | |
- AbsSpinnerCompat(Context context) { | |
- super(context); | |
- initAbsSpinner(); | |
- } | |
- | |
- AbsSpinnerCompat(Context context, AttributeSet attrs) { | |
- this(context, attrs, 0); | |
- } | |
- | |
- AbsSpinnerCompat(Context context, AttributeSet attrs, int defStyle) { | |
- super(context, attrs, defStyle); | |
- initAbsSpinner(); | |
- } | |
- | |
- /** | |
- * 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 paddingLeft = getPaddingLeft(); | |
- final int paddingTop = getPaddingTop(); | |
- final int paddingRight = getPaddingRight(); | |
- final int paddingBottom = getPaddingBottom(); | |
- | |
- mSpinnerPadding.left = paddingLeft > mSelectionLeftPadding ? paddingLeft | |
- : mSelectionLeftPadding; | |
- mSpinnerPadding.top = paddingTop > mSelectionTopPadding ? paddingTop | |
- : mSelectionTopPadding; | |
- mSpinnerPadding.right = paddingRight > mSelectionRightPadding ? paddingRight | |
- : mSelectionRightPadding; | |
- mSpinnerPadding.bottom = paddingBottom > mSelectionBottomPadding ? paddingBottom | |
- : 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.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()); | |
- | |
- heightSize = ViewCompat.resolveSizeAndState(preferredHeight, heightMeasureSpec, 0); | |
- widthSize = ViewCompat.resolveSizeAndState(preferredWidth, widthMeasureSpec, 0); | |
- | |
- 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 AbsSpinnerCompat.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 AbsSpinnerCompat#onSaveInstanceState()} | |
- */ | |
- SavedState(Parcelable superState) { | |
- super(superState); | |
- } | |
- | |
- /** | |
- * Constructor called from {@link #CREATOR} | |
- */ | |
- 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(); | |
- } | |
- } | |
-} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/ActionBarContextView.java appcampat-v7-23.0.0/android/support/v7/internal/widget/ActionBarContextView.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/ActionBarContextView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/ActionBarContextView.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -17,32 +17,26 @@ | |
package android.support.v7.internal.widget; | |
import android.content.Context; | |
-import android.content.res.TypedArray; | |
import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
-import android.support.v4.view.ViewCompat; | |
-import android.support.v4.view.ViewPropertyAnimatorCompat; | |
-import android.support.v4.view.ViewPropertyAnimatorListener; | |
import android.support.v7.appcompat.R; | |
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet; | |
+import android.support.v7.internal.view.menu.MenuBuilder; | |
import android.support.v7.view.ActionMode; | |
import android.support.v7.widget.ActionMenuPresenter; | |
import android.support.v7.widget.ActionMenuView; | |
-import android.support.v7.internal.view.menu.MenuBuilder; | |
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; | |
/** | |
* @hide | |
*/ | |
-public class ActionBarContextView extends AbsActionBarView implements ViewPropertyAnimatorListener { | |
+public class ActionBarContextView extends AbsActionBarView { | |
private static final String TAG = "ActionBarContextView"; | |
private CharSequence mTitle; | |
@@ -55,18 +49,9 @@ | |
private TextView mSubtitleView; | |
private int mTitleStyleRes; | |
private int mSubtitleStyleRes; | |
- private Drawable mSplitBackground; | |
private boolean mTitleOptional; | |
private int mCloseItemLayout; | |
- private ViewPropertyAnimatorCompatSet 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); | |
} | |
@@ -90,9 +75,6 @@ | |
mContentHeight = a.getLayoutDimension( | |
R.styleable.ActionMode_height, 0); | |
- mSplitBackground = a.getDrawable( | |
- R.styleable.ActionMode_backgroundSplit); | |
- | |
mCloseItemLayout = a.getResourceId( | |
R.styleable.ActionMode_closeItemLayout, | |
R.layout.abc_action_mode_close_item_material); | |
@@ -109,39 +91,6 @@ | |
} | |
} | |
- @Override | |
- public void setSplitToolbar(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.setSplitToolbar(split); | |
- } | |
- } | |
- | |
public void setContentHeight(int height) { | |
mContentHeight = height; | |
} | |
@@ -151,7 +100,7 @@ | |
removeView(mCustomView); | |
} | |
mCustomView = view; | |
- if (mTitleLayout != null) { | |
+ if (view != null && mTitleLayout != null) { | |
removeView(mTitleLayout); | |
mTitleLayout = null; | |
} | |
@@ -231,62 +180,23 @@ | |
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, | |
LayoutParams.MATCH_PARENT); | |
- if (!mSplitActionBar) { | |
- menu.addMenuPresenter(mActionMenuPresenter, mPopupContext); | |
- 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, mPopupContext); | |
- mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); | |
- mMenuView.setBackgroundDrawable(mSplitBackground); | |
- mSplitView.addView(mMenuView, layoutParams); | |
- } | |
- | |
- mAnimateInOnLayout = true; | |
+ menu.addMenuPresenter(mActionMenuPresenter, mPopupContext); | |
+ mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); | |
+ mMenuView.setBackgroundDrawable(null); | |
+ addView(mMenuView, layoutParams); | |
} | |
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 ViewPropertyAnimatorCompatSet a = mCurrentAnimation; | |
- if (a != null) { | |
- mCurrentAnimation = null; | |
- a.cancel(); | |
- } | |
} | |
public void killMode() { | |
- finishAnimation(); | |
removeAllViews(); | |
- if (mSplitView != null) { | |
- mSplitView.removeView(mMenuView); | |
- } | |
mCustomView = null; | |
mMenuView = null; | |
- mAnimateInOnLayout = false; | |
} | |
@Override | |
@@ -405,60 +315,6 @@ | |
} | |
} | |
- private ViewPropertyAnimatorCompatSet makeInAnimation() { | |
- ViewCompat.setTranslationX(mClose, -mClose.getWidth() - | |
- ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin); | |
- ViewPropertyAnimatorCompat buttonAnimator = ViewCompat.animate(mClose).translationX(0); | |
- buttonAnimator.setDuration(200); | |
- buttonAnimator.setListener(this); | |
- buttonAnimator.setInterpolator(new DecelerateInterpolator()); | |
- | |
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet(); | |
- 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++) { | |
- View child = mMenuView.getChildAt(i); | |
- ViewCompat.setScaleY(child, 0); | |
- ViewPropertyAnimatorCompat a = ViewCompat.animate(child).scaleY(1); | |
- a.setDuration(300); | |
- set.play(a); | |
- } | |
- } | |
- } | |
- | |
- return set; | |
- } | |
- | |
- private ViewPropertyAnimatorCompatSet makeOutAnimation() { | |
- ViewPropertyAnimatorCompat buttonAnimator = ViewCompat.animate(mClose) | |
- .translationX(-mClose.getWidth() - | |
- ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin); | |
- buttonAnimator.setDuration(200); | |
- buttonAnimator.setListener(this); | |
- buttonAnimator.setInterpolator(new DecelerateInterpolator()); | |
- | |
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet(); | |
- set.play(buttonAnimator); | |
- | |
- if (mMenuView != null) { | |
- final int count = mMenuView.getChildCount(); | |
- if (count > 0) { | |
- for (int i = 0; i < 0; i++) { | |
- View child = mMenuView.getChildAt(i); | |
- ViewCompat.setScaleY(child, 1); | |
- ViewPropertyAnimatorCompat a = ViewCompat.animate(child).scaleY(0); | |
- a.setDuration(300); | |
- set.play(a); | |
- } | |
- } | |
- } | |
- | |
- return set; | |
- } | |
- | |
@Override | |
protected void onLayout(boolean changed, int l, int t, int r, int b) { | |
final boolean isLayoutRtl = ViewUtils.isLayoutRtl(this); | |
@@ -473,13 +329,6 @@ | |
x = next(x, startMargin, isLayoutRtl); | |
x += positionChild(mClose, x, y, contentHeight, isLayoutRtl); | |
x = next(x, endMargin, isLayoutRtl); | |
- | |
- if (mAnimateInOnLayout) { | |
- mAnimationMode = ANIMATE_IN; | |
- mCurrentAnimation = makeInAnimation(); | |
- mCurrentAnimation.start(); | |
- mAnimateInOnLayout = false; | |
- } | |
} | |
if (mTitleLayout != null && mCustomView == null && mTitleLayout.getVisibility() != GONE) { | |
@@ -498,22 +347,6 @@ | |
} | |
@Override | |
- public void onAnimationStart(View view) { | |
- } | |
- | |
- @Override | |
- public void onAnimationEnd(View view) { | |
- if (mAnimationMode == ANIMATE_OUT) { | |
- killMode(); | |
- } | |
- mAnimationMode = ANIMATE_IDLE; | |
- } | |
- | |
- @Override | |
- public void onAnimationCancel(View view) { | |
- } | |
- | |
- @Override | |
public boolean shouldDelayChildPressedState() { | |
return false; | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/ActionBarOverlayLayout.java appcampat-v7-23.0.0/android/support/v7/internal/widget/ActionBarOverlayLayout.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/ActionBarOverlayLayout.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/ActionBarOverlayLayout.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -31,6 +31,7 @@ | |
import android.support.v4.view.ViewPropertyAnimatorListener; | |
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; | |
import android.support.v4.widget.ScrollerCompat; | |
+import android.support.v7.app.AppCompatDelegate; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.VersionUtils; | |
import android.support.v7.internal.view.menu.MenuPresenter; | |
@@ -58,7 +59,6 @@ | |
// The main UI elements that we handle the layout of. | |
private ContentFrameLayout mContent; | |
- private ActionBarContainer mActionBarBottom; | |
private ActionBarContainer mActionBarTop; | |
// Some interior UI elements. | |
@@ -88,7 +88,6 @@ | |
private ScrollerCompat mFlingEstimator; | |
private ViewPropertyAnimatorCompat mCurrentActionBarTopAnimator; | |
- private ViewPropertyAnimatorCompat mCurrentActionBarBottomAnimator; | |
private final ViewPropertyAnimatorListener mTopAnimatorListener | |
= new ViewPropertyAnimatorListenerAdapter() { | |
@@ -105,30 +104,11 @@ | |
} | |
}; | |
- private final ViewPropertyAnimatorListener mBottomAnimatorListener = | |
- new ViewPropertyAnimatorListenerAdapter() { | |
- @Override | |
- public void onAnimationEnd(View view) { | |
- mCurrentActionBarBottomAnimator = null; | |
- mAnimatingForFling = false; | |
- } | |
- | |
- @Override | |
- public void onAnimationCancel(View view) { | |
- mCurrentActionBarBottomAnimator = null; | |
- mAnimatingForFling = false; | |
- } | |
- }; | |
- | |
private final Runnable mRemoveActionBarHideOffset = new Runnable() { | |
public void run() { | |
haltActionBarHideOffsetAnimations(); | |
mCurrentActionBarTopAnimator = ViewCompat.animate(mActionBarTop).translationY(0) | |
.setListener(mTopAnimatorListener); | |
- if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) { | |
- mCurrentActionBarBottomAnimator = ViewCompat.animate(mActionBarBottom).translationY(0) | |
- .setListener(mBottomAnimatorListener); | |
- } | |
} | |
}; | |
@@ -138,11 +118,6 @@ | |
mCurrentActionBarTopAnimator = ViewCompat.animate(mActionBarTop) | |
.translationY(-mActionBarTop.getHeight()) | |
.setListener(mTopAnimatorListener); | |
- if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) { | |
- mCurrentActionBarBottomAnimator = ViewCompat.animate(mActionBarBottom) | |
- .translationY(mActionBarBottom.getHeight()) | |
- .setListener(mBottomAnimatorListener); | |
- } | |
} | |
}; | |
@@ -310,11 +285,8 @@ | |
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0; | |
final Rect systemInsets = insets; | |
- // The top and bottom action bars are always within the content area. | |
+ // The top action bar is always within the content area. | |
boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true); | |
- if (mActionBarBottom != null) { | |
- changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true); | |
- } | |
mBaseInnerInsets.set(systemInsets); | |
ViewUtils.computeFitSystemWindows(this, mBaseInnerInsets, mBaseContentInsets); | |
@@ -374,18 +346,6 @@ | |
childState = ViewUtils.combineMeasuredStates(childState, | |
ViewCompat.getMeasuredState(mActionBarTop)); | |
- // xlarge screen layout doesn't have bottom action bar. | |
- if (mActionBarBottom != null) { | |
- measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0); | |
- lp = (LayoutParams) mActionBarBottom.getLayoutParams(); | |
- maxWidth = Math.max(maxWidth, | |
- mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); | |
- maxHeight = Math.max(maxHeight, | |
- mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); | |
- childState = ViewUtils.combineMeasuredStates(childState, | |
- ViewCompat.getMeasuredState(mActionBarBottom)); | |
- } | |
- | |
final int vis = ViewCompat.getWindowSystemUiVisibility(this); | |
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0; | |
@@ -406,17 +366,6 @@ | |
topInset = mActionBarTop.getMeasuredHeight(); | |
} | |
- if (mDecorToolbar.isSplit()) { | |
- // If action bar is split, adjust bottom insets for it. | |
- if (mActionBarBottom != null) { | |
- if (stable) { | |
- bottomInset = mActionBarHeight; | |
- } else { | |
- bottomInset = mActionBarBottom.getMeasuredHeight(); | |
- } | |
- } | |
- } | |
- | |
// If the window has not requested system UI layout flags, we need to | |
// make sure its content is not being covered by system UI... though it | |
// will still be covered by the action bar if they have requested it to | |
@@ -483,12 +432,7 @@ | |
final int height = child.getMeasuredHeight(); | |
int childLeft = parentLeft + lp.leftMargin; | |
- int childTop; | |
- if (child == mActionBarBottom) { | |
- childTop = parentBottom - height - lp.bottomMargin; | |
- } else { | |
- childTop = parentTop + lp.topMargin; | |
- } | |
+ int childTop = parentTop + lp.topMargin; | |
child.layout(childLeft, childTop, childLeft + width, childTop + height); | |
} | |
@@ -586,7 +530,6 @@ | |
mContent = (ContentFrameLayout) findViewById(R.id.action_bar_activity_content); | |
mActionBarTop = (ActionBarContainer) findViewById(R.id.action_bar_container); | |
mDecorToolbar = getDecorToolbar(findViewById(R.id.action_bar)); | |
- mActionBarBottom = (ActionBarContainer) findViewById(R.id.split_action_bar); | |
} | |
} | |
@@ -624,12 +567,6 @@ | |
final int topHeight = mActionBarTop.getHeight(); | |
offset = Math.max(0, Math.min(offset, topHeight)); | |
ViewCompat.setTranslationY(mActionBarTop, -offset); | |
- if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) { | |
- // Match the hide offset proportionally for a split bar | |
- final float fOffset = (float) offset / topHeight; | |
- final int bOffset = (int) (mActionBarBottom.getHeight() * fOffset); | |
- ViewCompat.setTranslationY(mActionBarBottom, bOffset); | |
- } | |
} | |
private void haltActionBarHideOffsetAnimations() { | |
@@ -638,9 +575,6 @@ | |
if (mCurrentActionBarTopAnimator != null) { | |
mCurrentActionBarTopAnimator.cancel(); | |
} | |
- if (mCurrentActionBarBottomAnimator != null) { | |
- mCurrentActionBarBottomAnimator.cancel(); | |
- } | |
} | |
private void postRemoveActionBarHideOffset() { | |
@@ -697,7 +631,7 @@ | |
case Window.FEATURE_INDETERMINATE_PROGRESS: | |
mDecorToolbar.initIndeterminateProgress(); | |
break; | |
- case Window.FEATURE_ACTION_BAR_OVERLAY: | |
+ case AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR_OVERLAY: | |
setOverlayMode(true); | |
break; | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/ActivityChooserModel.java appcampat-v7-23.0.0/android/support/v7/internal/widget/ActivityChooserModel.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/ActivityChooserModel.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/ActivityChooserModel.java 2015-07-15 08:50:04.000000000 +0900 | |
@@ -16,22 +16,21 @@ | |
package android.support.v7.internal.widget; | |
+import org.xmlpull.v1.XmlPullParser; | |
+import org.xmlpull.v1.XmlPullParserException; | |
+import org.xmlpull.v1.XmlSerializer; | |
+ | |
import android.content.ComponentName; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.content.pm.ResolveInfo; | |
import android.database.DataSetObservable; | |
import android.os.AsyncTask; | |
-import android.os.Build; | |
import android.support.v4.os.AsyncTaskCompat; | |
import android.text.TextUtils; | |
import android.util.Log; | |
import android.util.Xml; | |
-import org.xmlpull.v1.XmlPullParser; | |
-import org.xmlpull.v1.XmlPullParserException; | |
-import org.xmlpull.v1.XmlSerializer; | |
- | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
@@ -576,7 +575,7 @@ | |
mHistoricalRecordsChanged = false; | |
if (!TextUtils.isEmpty(mHistoryFileName)) { | |
AsyncTaskCompat.executeParallel(new PersistHistoryAsyncTask(), | |
- mHistoricalRecords, mHistoryFileName); | |
+ new ArrayList<HistoricalRecord>(mHistoricalRecords), mHistoryFileName); | |
} | |
} | |
@@ -918,29 +917,31 @@ | |
private final class DefaultSorter implements ActivitySorter { | |
private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f; | |
- private final Map<String, ActivityResolveInfo> mPackageNameToActivityMap = | |
- new HashMap<String, ActivityResolveInfo>(); | |
+ private final Map<ComponentName, ActivityResolveInfo> mPackageNameToActivityMap = | |
+ new HashMap<ComponentName, ActivityResolveInfo>(); | |
public void sort(Intent intent, List<ActivityResolveInfo> activities, | |
List<HistoricalRecord> historicalRecords) { | |
- Map<String, ActivityResolveInfo> packageNameToActivityMap = | |
+ Map<ComponentName, ActivityResolveInfo> componentNameToActivityMap = | |
mPackageNameToActivityMap; | |
- packageNameToActivityMap.clear(); | |
+ componentNameToActivityMap.clear(); | |
final int activityCount = activities.size(); | |
for (int i = 0; i < activityCount; i++) { | |
ActivityResolveInfo activity = activities.get(i); | |
activity.weight = 0.0f; | |
- String packageName = activity.resolveInfo.activityInfo.packageName; | |
- packageNameToActivityMap.put(packageName, activity); | |
+ ComponentName componentName = new ComponentName( | |
+ activity.resolveInfo.activityInfo.packageName, | |
+ activity.resolveInfo.activityInfo.name); | |
+ componentNameToActivityMap.put(componentName, activity); | |
} | |
final int lastShareIndex = historicalRecords.size() - 1; | |
float nextRecordWeight = 1; | |
for (int i = lastShareIndex; i >= 0; i--) { | |
HistoricalRecord historicalRecord = historicalRecords.get(i); | |
- String packageName = historicalRecord.activity.getPackageName(); | |
- ActivityResolveInfo activity = packageNameToActivityMap.get(packageName); | |
+ ComponentName componentName = historicalRecord.activity; | |
+ ActivityResolveInfo activity = componentNameToActivityMap.get(componentName); | |
if (activity != null) { | |
activity.weight += historicalRecord.weight * nextRecordWeight; | |
nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT; | |
@@ -957,9 +958,6 @@ | |
} | |
} | |
- /** | |
- * Command for reading the historical records from a file off the UI thread. | |
- */ | |
private void readHistoricalDataImpl() { | |
FileInputStream fis = null; | |
try { | |
@@ -972,7 +970,7 @@ | |
} | |
try { | |
XmlPullParser parser = Xml.newPullParser(); | |
- parser.setInput(fis, null); | |
+ parser.setInput(fis, "UTF-8"); | |
int type = XmlPullParser.START_DOCUMENT; | |
while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/AdapterViewCompat.java appcampat-v7-23.0.0/android/support/v7/internal/widget/AdapterViewCompat.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/AdapterViewCompat.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/AdapterViewCompat.java 1970-01-01 09:00:00.000000000 +0900 | |
@@ -1,1150 +0,0 @@ | |
-package android.support.v7.internal.widget; | |
- | |
-/* | |
- * 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. | |
- */ | |
- | |
-import android.content.Context; | |
-import android.database.DataSetObserver; | |
-import android.os.Parcelable; | |
-import android.os.SystemClock; | |
-import android.util.AttributeSet; | |
-import android.util.SparseArray; | |
-import android.view.ContextMenu; | |
-import android.view.ContextMenu.ContextMenuInfo; | |
-import android.view.SoundEffectConstants; | |
-import android.view.View; | |
-import android.view.ViewDebug; | |
-import android.view.ViewGroup; | |
-import android.view.accessibility.AccessibilityEvent; | |
-import android.widget.Adapter; | |
-import android.widget.AdapterView; | |
-import android.widget.ListView; | |
- | |
- | |
-/** | |
- * An AdapterView is a view whose children are determined by an {@link android.widget.Adapter}. | |
- * | |
- * <p> | |
- * See {@link ListView}, {@link android.widget.GridView}, {@link android.widget.Spinner} and | |
- * {@link android.widget.Gallery} for commonly used subclasses of AdapterView. | |
- * | |
- * <div class="special reference"> | |
- * <h3>Developer Guides</h3> | |
- * <p>For more information about using AdapterView, read the | |
- * <a href="{@docRoot}guide/topics/ui/binding.html">Binding to Data with AdapterView</a> | |
- * developer guide.</p></div> | |
- * | |
- * @hide | |
- */ | |
-public abstract class AdapterViewCompat<T extends Adapter> extends ViewGroup { | |
- | |
- /** | |
- * The item view type returned by {@link Adapter#getItemViewType(int)} when | |
- * the adapter does not want the item's view recycled. | |
- */ | |
- static final int ITEM_VIEW_TYPE_IGNORE = -1; | |
- | |
- /** | |
- * The item view type returned by {@link Adapter#getItemViewType(int)} when | |
- * the item is a header or footer. | |
- */ | |
- static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2; | |
- | |
- /** | |
- * The position of the first child displayed | |
- */ | |
- @ViewDebug.ExportedProperty(category = "scrolling") | |
- int mFirstPosition = 0; | |
- | |
- /** | |
- * The offset in pixels from the top of the AdapterView to the top | |
- * of the view to select during the next layout. | |
- */ | |
- int mSpecificTop; | |
- | |
- /** | |
- * Position from which to start looking for mSyncRowId | |
- */ | |
- int mSyncPosition; | |
- | |
- /** | |
- * Row id to look for when data has changed | |
- */ | |
- long mSyncRowId = INVALID_ROW_ID; | |
- | |
- /** | |
- * Height of the view when mSyncPosition and mSyncRowId where set | |
- */ | |
- long mSyncHeight; | |
- | |
- /** | |
- * True if we need to sync to mSyncRowId | |
- */ | |
- boolean mNeedSync = false; | |
- | |
- /** | |
- * Indicates whether to sync based on the selection or position. Possible | |
- * values are {@link #SYNC_SELECTED_POSITION} or | |
- * {@link #SYNC_FIRST_POSITION}. | |
- */ | |
- int mSyncMode; | |
- | |
- /** | |
- * Our height after the last layout | |
- */ | |
- private int mLayoutHeight; | |
- | |
- /** | |
- * Sync based on the selected child | |
- */ | |
- static final int SYNC_SELECTED_POSITION = 0; | |
- | |
- /** | |
- * Sync based on the first child displayed | |
- */ | |
- static final int SYNC_FIRST_POSITION = 1; | |
- | |
- /** | |
- * Maximum amount of time to spend in {@link #findSyncPosition()} | |
- */ | |
- static final int SYNC_MAX_DURATION_MILLIS = 100; | |
- | |
- /** | |
- * Indicates that this view is currently being laid out. | |
- */ | |
- boolean mInLayout = false; | |
- | |
- /** | |
- * The listener that receives notifications when an item is selected. | |
- */ | |
- OnItemSelectedListener mOnItemSelectedListener; | |
- | |
- /** | |
- * The listener that receives notifications when an item is clicked. | |
- */ | |
- OnItemClickListener mOnItemClickListener; | |
- | |
- /** | |
- * The listener that receives notifications when an item is long clicked. | |
- */ | |
- OnItemLongClickListener mOnItemLongClickListener; | |
- | |
- /** | |
- * True if the data has changed since the last layout | |
- */ | |
- boolean mDataChanged; | |
- | |
- /** | |
- * The position within the adapter's data set of the item to select | |
- * during the next layout. | |
- */ | |
- @ViewDebug.ExportedProperty(category = "list") | |
- int mNextSelectedPosition = INVALID_POSITION; | |
- | |
- /** | |
- * The item id of the item to select during the next layout. | |
- */ | |
- long mNextSelectedRowId = INVALID_ROW_ID; | |
- | |
- /** | |
- * The position within the adapter's data set of the currently selected item. | |
- */ | |
- @ViewDebug.ExportedProperty(category = "list") | |
- int mSelectedPosition = INVALID_POSITION; | |
- | |
- /** | |
- * The item id of the currently selected item. | |
- */ | |
- long mSelectedRowId = INVALID_ROW_ID; | |
- | |
- /** | |
- * View to show if there are no items to show. | |
- */ | |
- private View mEmptyView; | |
- | |
- /** | |
- * The number of items in the current adapter. | |
- */ | |
- @ViewDebug.ExportedProperty(category = "list") | |
- int mItemCount; | |
- | |
- /** | |
- * The number of items in the adapter before a data changed event occurred. | |
- */ | |
- int mOldItemCount; | |
- | |
- /** | |
- * Represents an invalid position. All valid positions are in the range 0 to 1 less than the | |
- * number of items in the current adapter. | |
- */ | |
- public static final int INVALID_POSITION = -1; | |
- | |
- /** | |
- * Represents an empty or invalid row id | |
- */ | |
- public static final long INVALID_ROW_ID = Long.MIN_VALUE; | |
- | |
- /** | |
- * The last selected position we used when notifying | |
- */ | |
- int mOldSelectedPosition = INVALID_POSITION; | |
- | |
- /** | |
- * The id of the last selected position we used when notifying | |
- */ | |
- long mOldSelectedRowId = INVALID_ROW_ID; | |
- | |
- /** | |
- * Indicates what focusable state is requested when calling setFocusable(). | |
- * In addition to this, this view has other criteria for actually | |
- * determining the focusable state (such as whether its empty or the text | |
- * filter is shown). | |
- * | |
- * @see #setFocusable(boolean) | |
- * @see #checkFocus() | |
- */ | |
- private boolean mDesiredFocusableState; | |
- private boolean mDesiredFocusableInTouchModeState; | |
- | |
- private SelectionNotifier mSelectionNotifier; | |
- /** | |
- * When set to true, calls to requestLayout() will not propagate up the parent hierarchy. | |
- * This is used to layout the children during a layout pass. | |
- */ | |
- boolean mBlockLayoutRequests = false; | |
- | |
- AdapterViewCompat(Context context) { | |
- super(context); | |
- } | |
- | |
- AdapterViewCompat(Context context, AttributeSet attrs) { | |
- super(context, attrs); | |
- } | |
- | |
- AdapterViewCompat(Context context, AttributeSet attrs, int defStyle) { | |
- super(context, attrs, defStyle); | |
- } | |
- | |
- /** | |
- * Interface definition for a callback to be invoked when an item in this | |
- * AdapterView has been clicked. | |
- */ | |
- public interface OnItemClickListener { | |
- | |
- /** | |
- * Callback method to be invoked when an item in this AdapterView has | |
- * been clicked. | |
- * <p> | |
- * Implementers can call getItemAtPosition(position) if they need | |
- * to access the data associated with the selected item. | |
- * | |
- * @param parent The AdapterView where the click happened. | |
- * @param view The view within the AdapterView that was clicked (this | |
- * will be a view provided by the adapter) | |
- * @param position The position of the view in the adapter. | |
- * @param id The row id of the item that was clicked. | |
- */ | |
- void onItemClick(AdapterViewCompat<?> parent, View view, int position, long id); | |
- } | |
- | |
- class OnItemClickListenerWrapper implements AdapterView.OnItemClickListener { | |
- | |
- private final OnItemClickListener mWrappedListener; | |
- | |
- public OnItemClickListenerWrapper(OnItemClickListener listener) { | |
- mWrappedListener = listener; | |
- } | |
- | |
- @Override | |
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | |
- mWrappedListener.onItemClick(AdapterViewCompat.this, view, position, id); | |
- } | |
- } | |
- | |
- /** | |
- * Register a callback to be invoked when an item in this AdapterView has | |
- * been clicked. | |
- * | |
- * @param listener The callback that will be invoked. | |
- */ | |
- public void setOnItemClickListener(OnItemClickListener listener) { | |
- mOnItemClickListener = listener; | |
- } | |
- | |
- /** | |
- * @return The callback to be invoked with an item in this AdapterView has | |
- * been clicked, or null id no callback has been set. | |
- */ | |
- public final OnItemClickListener getOnItemClickListener() { | |
- return mOnItemClickListener; | |
- } | |
- | |
- /** | |
- * Call the OnItemClickListener, if it is defined. | |
- * | |
- * @param view The view within the AdapterView that was clicked. | |
- * @param position The position of the view in the adapter. | |
- * @param id The row id of the item that was clicked. | |
- * @return True if there was an assigned OnItemClickListener that was | |
- * called, false otherwise is returned. | |
- */ | |
- public boolean performItemClick(View view, int position, long id) { | |
- if (mOnItemClickListener != null) { | |
- playSoundEffect(SoundEffectConstants.CLICK); | |
- if (view != null) { | |
- view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); | |
- } | |
- mOnItemClickListener.onItemClick(this, view, position, id); | |
- return true; | |
- } | |
- | |
- return false; | |
- } | |
- | |
- /** | |
- * Interface definition for a callback to be invoked when an item in this | |
- * view has been clicked and held. | |
- */ | |
- public interface OnItemLongClickListener { | |
- /** | |
- * Callback method to be invoked when an item in this view has been | |
- * clicked and held. | |
- * | |
- * Implementers can call getItemAtPosition(position) if they need to access | |
- * the data associated with the selected item. | |
- * | |
- * @param parent The AbsListView where the click happened | |
- * @param view The view within the AbsListView that was clicked | |
- * @param position The position of the view in the list | |
- * @param id The row id of the item that was clicked | |
- * | |
- * @return true if the callback consumed the long click, false otherwise | |
- */ | |
- boolean onItemLongClick(AdapterViewCompat<?> parent, View view, int position, long id); | |
- } | |
- | |
- | |
- /** | |
- * Register a callback to be invoked when an item in this AdapterView has | |
- * been clicked and held | |
- * | |
- * @param listener The callback that will run | |
- */ | |
- public void setOnItemLongClickListener(OnItemLongClickListener listener) { | |
- if (!isLongClickable()) { | |
- setLongClickable(true); | |
- } | |
- mOnItemLongClickListener = listener; | |
- } | |
- | |
- /** | |
- * @return The callback to be invoked with an item in this AdapterView has | |
- * been clicked and held, or null id no callback as been set. | |
- */ | |
- public final OnItemLongClickListener getOnItemLongClickListener() { | |
- return mOnItemLongClickListener; | |
- } | |
- | |
- /** | |
- * Interface definition for a callback to be invoked when | |
- * an item in this view has been selected. | |
- */ | |
- public interface OnItemSelectedListener { | |
- /** | |
- * <p>Callback method to be invoked when an item in this view has been | |
- * selected. This callback is invoked only when the newly selected | |
- * position is different from the previously selected position or if | |
- * there was no selected item.</p> | |
- * | |
- * Impelmenters can call getItemAtPosition(position) if they need to access the | |
- * data associated with the selected item. | |
- * | |
- * @param parent The AdapterView where the selection happened | |
- * @param view The view within the AdapterView that was clicked | |
- * @param position The position of the view in the adapter | |
- * @param id The row id of the item that is selected | |
- */ | |
- void onItemSelected(AdapterViewCompat<?> parent, View view, int position, long id); | |
- | |
- /** | |
- * Callback method to be invoked when the selection disappears from this | |
- * view. The selection can disappear for instance when touch is activated | |
- * or when the adapter becomes empty. | |
- * | |
- * @param parent The AdapterView that now contains no selected item. | |
- */ | |
- void onNothingSelected(AdapterViewCompat<?> parent); | |
- } | |
- | |
- | |
- /** | |
- * Register a callback to be invoked when an item in this AdapterView has | |
- * been selected. | |
- * | |
- * @param listener The callback that will run | |
- */ | |
- public void setOnItemSelectedListener(OnItemSelectedListener listener) { | |
- mOnItemSelectedListener = listener; | |
- } | |
- | |
- public final OnItemSelectedListener getOnItemSelectedListener() { | |
- return mOnItemSelectedListener; | |
- } | |
- | |
- /** | |
- * Extra menu information provided to the | |
- * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) } | |
- * callback when a context menu is brought up for this AdapterView. | |
- * | |
- */ | |
- public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo { | |
- | |
- public AdapterContextMenuInfo(View targetView, int position, long id) { | |
- this.targetView = targetView; | |
- this.position = position; | |
- this.id = id; | |
- } | |
- | |
- /** | |
- * The child view for which the context menu is being displayed. This | |
- * will be one of the children of this AdapterView. | |
- */ | |
- public View targetView; | |
- | |
- /** | |
- * The position in the adapter for which the context menu is being | |
- * displayed. | |
- */ | |
- public int position; | |
- | |
- /** | |
- * The row id of the item for which the context menu is being displayed. | |
- */ | |
- public long id; | |
- } | |
- | |
- /** | |
- * Returns the adapter currently associated with this widget. | |
- * | |
- * @return The adapter used to provide this view's content. | |
- */ | |
- public abstract T getAdapter(); | |
- | |
- /** | |
- * Sets the adapter that provides the data and the views to represent the data | |
- * in this widget. | |
- * | |
- * @param adapter The adapter to use to create this view's content. | |
- */ | |
- public abstract void setAdapter(T adapter); | |
- | |
- /** | |
- * This method is not supported and throws an UnsupportedOperationException when called. | |
- * | |
- * @param child Ignored. | |
- * | |
- * @throws UnsupportedOperationException Every time this method is invoked. | |
- */ | |
- @Override | |
- public void addView(View child) { | |
- throw new UnsupportedOperationException("addView(View) is not supported in AdapterView"); | |
- } | |
- | |
- /** | |
- * This method is not supported and throws an UnsupportedOperationException when called. | |
- * | |
- * @param child Ignored. | |
- * @param index Ignored. | |
- * | |
- * @throws UnsupportedOperationException Every time this method is invoked. | |
- */ | |
- @Override | |
- public void addView(View child, int index) { | |
- throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView"); | |
- } | |
- | |
- /** | |
- * This method is not supported and throws an UnsupportedOperationException when called. | |
- * | |
- * @param child Ignored. | |
- * @param params Ignored. | |
- * | |
- * @throws UnsupportedOperationException Every time this method is invoked. | |
- */ | |
- @Override | |
- public void addView(View child, LayoutParams params) { | |
- throw new UnsupportedOperationException("addView(View, LayoutParams) " | |
- + "is not supported in AdapterView"); | |
- } | |
- | |
- /** | |
- * This method is not supported and throws an UnsupportedOperationException when called. | |
- * | |
- * @param child Ignored. | |
- * @param index Ignored. | |
- * @param params Ignored. | |
- * | |
- * @throws UnsupportedOperationException Every time this method is invoked. | |
- */ | |
- @Override | |
- public void addView(View child, int index, LayoutParams params) { | |
- throw new UnsupportedOperationException("addView(View, int, LayoutParams) " | |
- + "is not supported in AdapterView"); | |
- } | |
- | |
- /** | |
- * This method is not supported and throws an UnsupportedOperationException when called. | |
- * | |
- * @param child Ignored. | |
- * | |
- * @throws UnsupportedOperationException Every time this method is invoked. | |
- */ | |
- @Override | |
- public void removeView(View child) { | |
- throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView"); | |
- } | |
- | |
- /** | |
- * This method is not supported and throws an UnsupportedOperationException when called. | |
- * | |
- * @param index Ignored. | |
- * | |
- * @throws UnsupportedOperationException Every time this method is invoked. | |
- */ | |
- @Override | |
- public void removeViewAt(int index) { | |
- throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView"); | |
- } | |
- | |
- /** | |
- * This method is not supported and throws an UnsupportedOperationException when called. | |
- * | |
- * @throws UnsupportedOperationException Every time this method is invoked. | |
- */ | |
- @Override | |
- public void removeAllViews() { | |
- throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView"); | |
- } | |
- | |
- @Override | |
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) { | |
- mLayoutHeight = getHeight(); | |
- } | |
- | |
- /** | |
- * Return the position of the currently selected item within the adapter's data set | |
- * | |
- * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected. | |
- */ | |
- @ViewDebug.CapturedViewProperty | |
- public int getSelectedItemPosition() { | |
- return mNextSelectedPosition; | |
- } | |
- | |
- /** | |
- * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID} | |
- * if nothing is selected. | |
- */ | |
- @ViewDebug.CapturedViewProperty | |
- public long getSelectedItemId() { | |
- return mNextSelectedRowId; | |
- } | |
- | |
- /** | |
- * @return The view corresponding to the currently selected item, or null | |
- * if nothing is selected | |
- */ | |
- public abstract View getSelectedView(); | |
- | |
- /** | |
- * @return The data corresponding to the currently selected item, or | |
- * null if there is nothing selected. | |
- */ | |
- public Object getSelectedItem() { | |
- T adapter = getAdapter(); | |
- int selection = getSelectedItemPosition(); | |
- if (adapter != null && adapter.getCount() > 0 && selection >= 0) { | |
- return adapter.getItem(selection); | |
- } else { | |
- return null; | |
- } | |
- } | |
- | |
- /** | |
- * @return The number of items owned by the Adapter associated with this | |
- * AdapterView. (This is the number of data items, which may be | |
- * larger than the number of visible views.) | |
- */ | |
- @ViewDebug.CapturedViewProperty | |
- public int getCount() { | |
- return mItemCount; | |
- } | |
- | |
- /** | |
- * Get the position within the adapter's data set for the view, where view is a an adapter item | |
- * or a descendant of an adapter item. | |
- * | |
- * @param view an adapter item, or a descendant of an adapter item. This must be visible in this | |
- * AdapterView at the time of the call. | |
- * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION} | |
- * if the view does not correspond to a list item (or it is not currently visible). | |
- */ | |
- public int getPositionForView(View view) { | |
- View listItem = view; | |
- try { | |
- View v; | |
- while (!(v = (View) listItem.getParent()).equals(this)) { | |
- listItem = v; | |
- } | |
- } catch (ClassCastException e) { | |
- // We made it up to the window without find this list view | |
- return INVALID_POSITION; | |
- } | |
- | |
- // Search the children for the list item | |
- final int childCount = getChildCount(); | |
- for (int i = 0; i < childCount; i++) { | |
- if (getChildAt(i).equals(listItem)) { | |
- return mFirstPosition + i; | |
- } | |
- } | |
- | |
- // Child not found! | |
- return INVALID_POSITION; | |
- } | |
- | |
- /** | |
- * Returns the position within the adapter's data set for the first item | |
- * displayed on screen. | |
- * | |
- * @return The position within the adapter's data set | |
- */ | |
- public int getFirstVisiblePosition() { | |
- return mFirstPosition; | |
- } | |
- | |
- /** | |
- * Returns the position within the adapter's data set for the last item | |
- * displayed on screen. | |
- * | |
- * @return The position within the adapter's data set | |
- */ | |
- public int getLastVisiblePosition() { | |
- return mFirstPosition + getChildCount() - 1; | |
- } | |
- | |
- /** | |
- * Sets the currently selected item. To support accessibility subclasses that | |
- * override this method must invoke the overriden super method first. | |
- * | |
- * @param position Index (starting at 0) of the data item to be selected. | |
- */ | |
- public abstract void setSelection(int position); | |
- | |
- /** | |
- * Sets the view to show if the adapter is empty | |
- */ | |
- public void setEmptyView(View emptyView) { | |
- mEmptyView = emptyView; | |
- | |
- final T adapter = getAdapter(); | |
- final boolean empty = ((adapter == null) || adapter.isEmpty()); | |
- updateEmptyStatus(empty); | |
- } | |
- | |
- /** | |
- * When the current adapter is empty, the AdapterView can display a special view | |
- * call the empty view. The empty view is used to provide feedback to the user | |
- * that no data is available in this AdapterView. | |
- * | |
- * @return The view to show if the adapter is empty. | |
- */ | |
- public View getEmptyView() { | |
- return mEmptyView; | |
- } | |
- | |
- /** | |
- * Indicates whether this view is in filter mode. Filter mode can for instance | |
- * be enabled by a user when typing on the keyboard. | |
- * | |
- * @return True if the view is in filter mode, false otherwise. | |
- */ | |
- boolean isInFilterMode() { | |
- return false; | |
- } | |
- | |
- @Override | |
- public void setFocusable(boolean focusable) { | |
- final T adapter = getAdapter(); | |
- final boolean empty = adapter == null || adapter.getCount() == 0; | |
- | |
- mDesiredFocusableState = focusable; | |
- if (!focusable) { | |
- mDesiredFocusableInTouchModeState = false; | |
- } | |
- | |
- super.setFocusable(focusable && (!empty || isInFilterMode())); | |
- } | |
- | |
- @Override | |
- public void setFocusableInTouchMode(boolean focusable) { | |
- final T adapter = getAdapter(); | |
- final boolean empty = adapter == null || adapter.getCount() == 0; | |
- | |
- mDesiredFocusableInTouchModeState = focusable; | |
- if (focusable) { | |
- mDesiredFocusableState = true; | |
- } | |
- | |
- super.setFocusableInTouchMode(focusable && (!empty || isInFilterMode())); | |
- } | |
- | |
- void checkFocus() { | |
- final T adapter = getAdapter(); | |
- final boolean empty = adapter == null || adapter.getCount() == 0; | |
- final boolean focusable = !empty || isInFilterMode(); | |
- // The order in which we set focusable in touch mode/focusable may matter | |
- // for the client, see View.setFocusableInTouchMode() comments for more | |
- // details | |
- super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState); | |
- super.setFocusable(focusable && mDesiredFocusableState); | |
- if (mEmptyView != null) { | |
- updateEmptyStatus((adapter == null) || adapter.isEmpty()); | |
- } | |
- } | |
- | |
- /** | |
- * Update the status of the list based on the empty parameter. If empty is true and | |
- * we have an empty view, display it. In all the other cases, make sure that the listview | |
- * is VISIBLE and that the empty view is GONE (if it's not null). | |
- */ | |
- private void updateEmptyStatus(boolean empty) { | |
- if (isInFilterMode()) { | |
- empty = false; | |
- } | |
- | |
- if (empty) { | |
- if (mEmptyView != null) { | |
- mEmptyView.setVisibility(View.VISIBLE); | |
- setVisibility(View.GONE); | |
- } else { | |
- // If the caller just removed our empty view, make sure the list view is visible | |
- setVisibility(View.VISIBLE); | |
- } | |
- | |
- // We are now GONE, so pending layouts will not be dispatched. | |
- // Force one here to make sure that the state of the list matches | |
- // the state of the adapter. | |
- if (mDataChanged) { | |
- this.onLayout(false, getLeft(), getTop(), getRight(), getBottom()); | |
- } | |
- } else { | |
- if (mEmptyView != null) mEmptyView.setVisibility(View.GONE); | |
- setVisibility(View.VISIBLE); | |
- } | |
- } | |
- | |
- /** | |
- * Gets the data associated with the specified position in the list. | |
- * | |
- * @param position Which data to get | |
- * @return The data associated with the specified position in the list | |
- */ | |
- public Object getItemAtPosition(int position) { | |
- T adapter = getAdapter(); | |
- return (adapter == null || position < 0) ? null : adapter.getItem(position); | |
- } | |
- | |
- public long getItemIdAtPosition(int position) { | |
- T adapter = getAdapter(); | |
- return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position); | |
- } | |
- | |
- @Override | |
- public void setOnClickListener(OnClickListener l) { | |
- throw new RuntimeException("Don't call setOnClickListener for an AdapterView. " | |
- + "You probably want setOnItemClickListener instead"); | |
- } | |
- | |
- /** | |
- * Override to prevent freezing of any views created by the adapter. | |
- */ | |
- @Override | |
- protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { | |
- dispatchFreezeSelfOnly(container); | |
- } | |
- | |
- /** | |
- * Override to prevent thawing of any views created by the adapter. | |
- */ | |
- @Override | |
- protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { | |
- dispatchThawSelfOnly(container); | |
- } | |
- | |
- class AdapterDataSetObserver extends DataSetObserver { | |
- | |
- private Parcelable mInstanceState = null; | |
- | |
- @Override | |
- public void onChanged() { | |
- mDataChanged = true; | |
- mOldItemCount = mItemCount; | |
- mItemCount = getAdapter().getCount(); | |
- | |
- // Detect the case where a cursor that was previously invalidated has | |
- // been repopulated with new data. | |
- if (AdapterViewCompat.this.getAdapter().hasStableIds() && mInstanceState != null | |
- && mOldItemCount == 0 && mItemCount > 0) { | |
- AdapterViewCompat.this.onRestoreInstanceState(mInstanceState); | |
- mInstanceState = null; | |
- } else { | |
- rememberSyncState(); | |
- } | |
- checkFocus(); | |
- requestLayout(); | |
- } | |
- | |
- @Override | |
- public void onInvalidated() { | |
- mDataChanged = true; | |
- | |
- if (AdapterViewCompat.this.getAdapter().hasStableIds()) { | |
- // Remember the current state for the case where our hosting activity is being | |
- // stopped and later restarted | |
- mInstanceState = AdapterViewCompat.this.onSaveInstanceState(); | |
- } | |
- | |
- // Data is invalid so we should reset our state | |
- mOldItemCount = mItemCount; | |
- mItemCount = 0; | |
- mSelectedPosition = INVALID_POSITION; | |
- mSelectedRowId = INVALID_ROW_ID; | |
- mNextSelectedPosition = INVALID_POSITION; | |
- mNextSelectedRowId = INVALID_ROW_ID; | |
- mNeedSync = false; | |
- | |
- checkFocus(); | |
- requestLayout(); | |
- } | |
- | |
- public void clearSavedState() { | |
- mInstanceState = null; | |
- } | |
- } | |
- | |
- @Override | |
- protected void onDetachedFromWindow() { | |
- super.onDetachedFromWindow(); | |
- removeCallbacks(mSelectionNotifier); | |
- } | |
- | |
- private class SelectionNotifier implements Runnable { | |
- public void run() { | |
- if (mDataChanged) { | |
- // Data has changed between when this SelectionNotifier | |
- // was posted and now. We need to wait until the AdapterView | |
- // has been synched to the new data. | |
- if (getAdapter() != null) { | |
- post(this); | |
- } | |
- } else { | |
- fireOnSelected(); | |
- } | |
- } | |
- } | |
- | |
- void selectionChanged() { | |
- if (mOnItemSelectedListener != null) { | |
- if (mInLayout || mBlockLayoutRequests) { | |
- // If we are in a layout traversal, defer notification | |
- // by posting. This ensures that the view tree is | |
- // in a consistent state and is able to accomodate | |
- // new layout or invalidate requests. | |
- if (mSelectionNotifier == null) { | |
- mSelectionNotifier = new SelectionNotifier(); | |
- } | |
- post(mSelectionNotifier); | |
- } else { | |
- fireOnSelected(); | |
- } | |
- } | |
- | |
- // we fire selection events here not in View | |
- if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) { | |
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); | |
- } | |
- } | |
- | |
- private void fireOnSelected() { | |
- if (mOnItemSelectedListener == null) | |
- return; | |
- | |
- int selection = this.getSelectedItemPosition(); | |
- if (selection >= 0) { | |
- View v = getSelectedView(); | |
- mOnItemSelectedListener.onItemSelected(this, v, selection, | |
- getAdapter().getItemId(selection)); | |
- } else { | |
- mOnItemSelectedListener.onNothingSelected(this); | |
- } | |
- } | |
- | |
- @Override | |
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { | |
- View selectedView = getSelectedView(); | |
- if (selectedView != null && selectedView.getVisibility() == VISIBLE | |
- && selectedView.dispatchPopulateAccessibilityEvent(event)) { | |
- return true; | |
- } | |
- return false; | |
- } | |
- | |
- @Override | |
- protected boolean canAnimate() { | |
- return super.canAnimate() && mItemCount > 0; | |
- } | |
- | |
- void handleDataChanged() { | |
- final int count = mItemCount; | |
- boolean found = false; | |
- | |
- if (count > 0) { | |
- | |
- int newPos; | |
- | |
- // Find the row we are supposed to sync to | |
- if (mNeedSync) { | |
- // Update this first, since setNextSelectedPositionInt inspects | |
- // it | |
- mNeedSync = false; | |
- | |
- // See if we can find a position in the new data with the same | |
- // id as the old selection | |
- newPos = findSyncPosition(); | |
- if (newPos >= 0) { | |
- // Verify that new selection is selectable | |
- int selectablePos = lookForSelectablePosition(newPos, true); | |
- if (selectablePos == newPos) { | |
- // Same row id is selected | |
- setNextSelectedPositionInt(newPos); | |
- found = true; | |
- } | |
- } | |
- } | |
- if (!found) { | |
- // Try to use the same position if we can't find matching data | |
- newPos = getSelectedItemPosition(); | |
- | |
- // Pin position to the available range | |
- if (newPos >= count) { | |
- newPos = count - 1; | |
- } | |
- if (newPos < 0) { | |
- newPos = 0; | |
- } | |
- | |
- // Make sure we select something selectable -- first look down | |
- int selectablePos = lookForSelectablePosition(newPos, true); | |
- if (selectablePos < 0) { | |
- // Looking down didn't work -- try looking up | |
- selectablePos = lookForSelectablePosition(newPos, false); | |
- } | |
- if (selectablePos >= 0) { | |
- setNextSelectedPositionInt(selectablePos); | |
- checkSelectionChanged(); | |
- found = true; | |
- } | |
- } | |
- } | |
- if (!found) { | |
- // Nothing is selected | |
- mSelectedPosition = INVALID_POSITION; | |
- mSelectedRowId = INVALID_ROW_ID; | |
- mNextSelectedPosition = INVALID_POSITION; | |
- mNextSelectedRowId = INVALID_ROW_ID; | |
- mNeedSync = false; | |
- checkSelectionChanged(); | |
- } | |
- } | |
- | |
- void checkSelectionChanged() { | |
- if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) { | |
- selectionChanged(); | |
- mOldSelectedPosition = mSelectedPosition; | |
- mOldSelectedRowId = mSelectedRowId; | |
- } | |
- } | |
- | |
- /** | |
- * Searches the adapter for a position matching mSyncRowId. The search starts at mSyncPosition | |
- * and then alternates between moving up and moving down until 1) we find the right position, or | |
- * 2) we run out of time, or 3) we have looked at every position | |
- * | |
- * @return Position of the row that matches mSyncRowId, or {@link #INVALID_POSITION} if it can't | |
- * be found | |
- */ | |
- int findSyncPosition() { | |
- int count = mItemCount; | |
- | |
- if (count == 0) { | |
- return INVALID_POSITION; | |
- } | |
- | |
- long idToMatch = mSyncRowId; | |
- int seed = mSyncPosition; | |
- | |
- // If there isn't a selection don't hunt for it | |
- if (idToMatch == INVALID_ROW_ID) { | |
- return INVALID_POSITION; | |
- } | |
- | |
- // Pin seed to reasonable values | |
- seed = Math.max(0, seed); | |
- seed = Math.min(count - 1, seed); | |
- | |
- long endTime = SystemClock.uptimeMillis() + SYNC_MAX_DURATION_MILLIS; | |
- | |
- long rowId; | |
- | |
- // first position scanned so far | |
- int first = seed; | |
- | |
- // last position scanned so far | |
- int last = seed; | |
- | |
- // True if we should move down on the next iteration | |
- boolean next = false; | |
- | |
- // True when we have looked at the first item in the data | |
- boolean hitFirst; | |
- | |
- // True when we have looked at the last item in the data | |
- boolean hitLast; | |
- | |
- // Get the item ID locally (instead of getItemIdAtPosition), so | |
- // we need the adapter | |
- T adapter = getAdapter(); | |
- if (adapter == null) { | |
- return INVALID_POSITION; | |
- } | |
- | |
- while (SystemClock.uptimeMillis() <= endTime) { | |
- rowId = adapter.getItemId(seed); | |
- if (rowId == idToMatch) { | |
- // Found it! | |
- return seed; | |
- } | |
- | |
- hitLast = last == count - 1; | |
- hitFirst = first == 0; | |
- | |
- if (hitLast && hitFirst) { | |
- // Looked at everything | |
- break; | |
- } | |
- | |
- if (hitFirst || (next && !hitLast)) { | |
- // Either we hit the top, or we are trying to move down | |
- last++; | |
- seed = last; | |
- // Try going up next time | |
- next = false; | |
- } else if (hitLast || (!next && !hitFirst)) { | |
- // Either we hit the bottom, or we are trying to move up | |
- first--; | |
- seed = first; | |
- // Try going down next time | |
- next = true; | |
- } | |
- | |
- } | |
- | |
- return INVALID_POSITION; | |
- } | |
- | |
- /** | |
- * Find a position that can be selected (i.e., is not a separator). | |
- * | |
- * @param position The starting position to look at. | |
- * @param lookDown Whether to look down for other positions. | |
- * @return The next selectable position starting at position and then searching either up or | |
- * down. Returns {@link #INVALID_POSITION} if nothing can be found. | |
- */ | |
- int lookForSelectablePosition(int position, boolean lookDown) { | |
- return position; | |
- } | |
- | |
- /** | |
- * Utility to keep mSelectedPosition and mSelectedRowId in sync | |
- * @param position Our current position | |
- */ | |
- void setSelectedPositionInt(int position) { | |
- mSelectedPosition = position; | |
- mSelectedRowId = getItemIdAtPosition(position); | |
- } | |
- | |
- /** | |
- * Utility to keep mNextSelectedPosition and mNextSelectedRowId in sync | |
- * @param position Intended value for mSelectedPosition the next time we go | |
- * through layout | |
- */ | |
- void setNextSelectedPositionInt(int position) { | |
- mNextSelectedPosition = position; | |
- mNextSelectedRowId = getItemIdAtPosition(position); | |
- // If we are trying to sync to the selection, update that too | |
- if (mNeedSync && mSyncMode == SYNC_SELECTED_POSITION && position >= 0) { | |
- mSyncPosition = position; | |
- mSyncRowId = mNextSelectedRowId; | |
- } | |
- } | |
- | |
- /** | |
- * Remember enough information to restore the screen state when the data has | |
- * changed. | |
- * | |
- */ | |
- void rememberSyncState() { | |
- if (getChildCount() > 0) { | |
- mNeedSync = true; | |
- mSyncHeight = mLayoutHeight; | |
- if (mSelectedPosition >= 0) { | |
- // Sync the selection state | |
- View v = getChildAt(mSelectedPosition - mFirstPosition); | |
- mSyncRowId = mNextSelectedRowId; | |
- mSyncPosition = mNextSelectedPosition; | |
- if (v != null) { | |
- mSpecificTop = v.getTop(); | |
- } | |
- mSyncMode = SYNC_SELECTED_POSITION; | |
- } else { | |
- // Sync the based on the offset of the first view | |
- View v = getChildAt(0); | |
- T adapter = getAdapter(); | |
- if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) { | |
- mSyncRowId = adapter.getItemId(mFirstPosition); | |
- } else { | |
- mSyncRowId = NO_ID; | |
- } | |
- mSyncPosition = mFirstPosition; | |
- if (v != null) { | |
- mSpecificTop = v.getTop(); | |
- } | |
- mSyncMode = SYNC_FIRST_POSITION; | |
- } | |
- } | |
- } | |
-} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/AppCompatPopupWindow.java appcampat-v7-23.0.0/android/support/v7/internal/widget/AppCompatPopupWindow.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/AppCompatPopupWindow.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/AppCompatPopupWindow.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -19,6 +19,7 @@ | |
import android.annotation.TargetApi; | |
import android.content.Context; | |
import android.os.Build; | |
+import android.support.v4.widget.PopupWindowCompat; | |
import android.support.v7.appcompat.R; | |
import android.util.AttributeSet; | |
import android.util.Log; | |
@@ -35,15 +36,18 @@ | |
public class AppCompatPopupWindow extends PopupWindow { | |
private static final String TAG = "AppCompatPopupWindow"; | |
+ private static final boolean COMPAT_OVERLAP_ANCHOR = Build.VERSION.SDK_INT < 21; | |
- private final boolean mOverlapAnchor; | |
+ private boolean mOverlapAnchor; | |
public AppCompatPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs, | |
R.styleable.PopupWindow, defStyleAttr, 0); | |
- mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false); | |
+ if (a.hasValue(R.styleable.PopupWindow_overlapAnchor)) { | |
+ setSupportOverlapAnchor(a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false)); | |
+ } | |
// We re-set this for tinting purposes | |
setBackgroundDrawable(a.getDrawable(R.styleable.PopupWindow_android_popupBackground)); | |
a.recycle(); | |
@@ -57,7 +61,7 @@ | |
@Override | |
public void showAsDropDown(View anchor, int xoff, int yoff) { | |
- if (Build.VERSION.SDK_INT < 21 && mOverlapAnchor) { | |
+ if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) { | |
// If we're pre-L, emulate overlapAnchor by modifying the yOff | |
yoff -= anchor.getHeight(); | |
} | |
@@ -67,7 +71,7 @@ | |
@TargetApi(Build.VERSION_CODES.KITKAT) | |
@Override | |
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) { | |
- if (Build.VERSION.SDK_INT < 21 && mOverlapAnchor) { | |
+ if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) { | |
// If we're pre-L, emulate overlapAnchor by modifying the yOff | |
yoff -= anchor.getHeight(); | |
} | |
@@ -76,7 +80,7 @@ | |
@Override | |
public void update(View anchor, int xoff, int yoff, int width, int height) { | |
- if (Build.VERSION.SDK_INT < 21 && mOverlapAnchor) { | |
+ if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) { | |
// If we're pre-L, emulate overlapAnchor by modifying the yOff | |
yoff -= anchor.getHeight(); | |
} | |
@@ -117,4 +121,26 @@ | |
} | |
} | |
+ /** | |
+ * @hide | |
+ */ | |
+ public void setSupportOverlapAnchor(boolean overlapAnchor) { | |
+ if (COMPAT_OVERLAP_ANCHOR) { | |
+ mOverlapAnchor = overlapAnchor; | |
+ } else { | |
+ PopupWindowCompat.setOverlapAnchor(this, overlapAnchor); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * @hide | |
+ */ | |
+ public boolean getSupportOverlapAnchor() { | |
+ if (COMPAT_OVERLAP_ANCHOR) { | |
+ return mOverlapAnchor; | |
+ } else { | |
+ return PopupWindowCompat.getOverlapAnchor(this); | |
+ } | |
+ } | |
+ | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/DecorToolbar.java appcampat-v7-23.0.0/android/support/v7/internal/widget/DecorToolbar.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/DecorToolbar.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/DecorToolbar.java 2015-06-29 08:17:36.000000000 +0900 | |
@@ -20,6 +20,7 @@ | |
import android.content.Context; | |
import android.graphics.drawable.Drawable; | |
import android.os.Parcelable; | |
+import android.support.v4.view.ViewPropertyAnimatorCompat; | |
import android.support.v7.internal.view.menu.MenuBuilder; | |
import android.support.v7.internal.view.menu.MenuPresenter; | |
import android.util.SparseArray; | |
@@ -27,6 +28,7 @@ | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.view.Window; | |
+import android.widget.AdapterView; | |
import android.widget.SpinnerAdapter; | |
/** | |
@@ -39,7 +41,6 @@ | |
public interface DecorToolbar { | |
ViewGroup getViewGroup(); | |
Context getContext(); | |
- boolean isSplit(); | |
boolean hasExpandedActionView(); | |
void collapseActionView(); | |
void setWindowCallback(Window.Callback cb); | |
@@ -50,10 +51,6 @@ | |
void setSubtitle(CharSequence subtitle); | |
void initProgress(); | |
void initIndeterminateProgress(); | |
- boolean canSplit(); | |
- void setSplitView(ViewGroup splitView); | |
- void setSplitToolbar(boolean split); | |
- void setSplitWhenNarrow(boolean splitWhenNarrow); | |
boolean hasIcon(); | |
boolean hasLogo(); | |
void setIcon(int resId); | |
@@ -78,13 +75,14 @@ | |
void setHomeButtonEnabled(boolean enable); | |
int getNavigationMode(); | |
void setNavigationMode(int mode); | |
- void setDropdownParams(SpinnerAdapter adapter, AdapterViewCompat.OnItemSelectedListener listener); | |
+ void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener listener); | |
void setDropdownSelectedPosition(int position); | |
int getDropdownSelectedPosition(); | |
int getDropdownItemCount(); | |
void setCustomView(View view); | |
View getCustomView(); | |
void animateToVisibility(int visibility); | |
+ ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration); | |
void setNavigationIcon(Drawable icon); | |
void setNavigationIcon(int resId); | |
void setNavigationContentDescription(CharSequence description); | |
@@ -100,5 +98,4 @@ | |
void setMenuCallbacks(MenuPresenter.Callback presenterCallback, | |
MenuBuilder.Callback menuBuilderCallback); | |
Menu getMenu(); | |
- int getPopupTheme(); | |
} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/ScrollingTabContainerView.java appcampat-v7-23.0.0/android/support/v7/internal/widget/ScrollingTabContainerView.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/ScrollingTabContainerView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/ScrollingTabContainerView.java 2015-06-29 08:17:36.000000000 +0900 | |
@@ -26,6 +26,7 @@ | |
import android.support.v7.app.ActionBar; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.view.ActionBarPolicy; | |
+import android.support.v7.widget.AppCompatSpinner; | |
import android.support.v7.widget.AppCompatTextView; | |
import android.support.v7.widget.LinearLayoutCompat; | |
import android.text.TextUtils; | |
@@ -38,10 +39,12 @@ | |
import android.view.accessibility.AccessibilityNodeInfo; | |
import android.view.animation.DecelerateInterpolator; | |
import android.view.animation.Interpolator; | |
+import android.widget.AdapterView; | |
import android.widget.BaseAdapter; | |
import android.widget.HorizontalScrollView; | |
import android.widget.ImageView; | |
import android.widget.ListView; | |
+import android.widget.Spinner; | |
import android.widget.TextView; | |
import android.widget.Toast; | |
@@ -52,14 +55,14 @@ | |
* @hide | |
*/ | |
public class ScrollingTabContainerView extends HorizontalScrollView | |
- implements AdapterViewCompat.OnItemClickListener { | |
+ implements AdapterView.OnItemSelectedListener { | |
private static final String TAG = "ScrollingTabContainerView"; | |
Runnable mTabSelector; | |
private TabClickListener mTabClickListener; | |
private LinearLayoutCompat mTabLayout; | |
- private SpinnerCompat mTabSpinner; | |
+ private Spinner mTabSpinner; | |
private boolean mAllowCollapse; | |
int mMaxTabWidth; | |
@@ -206,12 +209,13 @@ | |
return tabLayout; | |
} | |
- private SpinnerCompat createSpinner() { | |
- final SpinnerCompat spinner = new SpinnerCompat(getContext(), null, | |
+ private Spinner createSpinner() { | |
+ final Spinner spinner = new AppCompatSpinner(getContext(), null, | |
R.attr.actionDropDownStyle); | |
spinner.setLayoutParams(new LinearLayoutCompat.LayoutParams( | |
- LinearLayoutCompat.LayoutParams.WRAP_CONTENT, LinearLayoutCompat.LayoutParams.MATCH_PARENT)); | |
- spinner.setOnItemClickListenerInt(this); | |
+ LinearLayoutCompat.LayoutParams.WRAP_CONTENT, | |
+ LinearLayoutCompat.LayoutParams.MATCH_PARENT)); | |
+ spinner.setOnItemSelectedListener(this); | |
return spinner; | |
} | |
@@ -362,11 +366,16 @@ | |
} | |
@Override | |
- public void onItemClick(AdapterViewCompat<?> parent, View view, int position, long id) { | |
+ public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { | |
TabView tabView = (TabView) view; | |
tabView.getTab().select(); | |
} | |
+ @Override | |
+ public void onNothingSelected(AdapterView<?> adapterView) { | |
+ // no-op | |
+ } | |
+ | |
private class TabView extends LinearLayoutCompat implements OnLongClickListener { | |
private final int[] BG_ATTRS = { | |
android.R.attr.background | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/SpinnerCompat.java appcampat-v7-23.0.0/android/support/v7/internal/widget/SpinnerCompat.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/SpinnerCompat.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/SpinnerCompat.java 1970-01-01 09:00:00.000000000 +0900 | |
@@ -1,1102 +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 android.support.v7.internal.widget; | |
- | |
-import android.app.AlertDialog; | |
-import android.content.Context; | |
-import android.content.DialogInterface; | |
-import android.database.DataSetObserver; | |
-import android.graphics.Rect; | |
-import android.graphics.drawable.Drawable; | |
-import android.os.Build; | |
-import android.os.Parcel; | |
-import android.os.Parcelable; | |
-import android.support.v4.view.GravityCompat; | |
-import android.support.v4.view.ViewCompat; | |
-import android.support.v7.appcompat.R; | |
-import android.support.v7.widget.ListPopupWindow; | |
-import android.util.AttributeSet; | |
-import android.util.Log; | |
-import android.view.Gravity; | |
-import android.view.MotionEvent; | |
-import android.view.View; | |
-import android.view.ViewGroup; | |
-import android.view.ViewTreeObserver; | |
-import android.widget.AdapterView; | |
-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 android.widget.Adapter} associated with this view. | |
- * | |
- * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner | |
- * tutorial</a>.</p> | |
- */ | |
-class SpinnerCompat extends AbsSpinnerCompat implements DialogInterface.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; | |
- | |
- /** | |
- * Forwarding listener used to implement drag-to-open. | |
- */ | |
- private ListPopupWindow.ForwardingListener mForwardingListener; | |
- | |
- private SpinnerPopup mPopup; | |
- | |
- private DropDownAdapter mTempAdapter; | |
- | |
- int mDropDownWidth; | |
- | |
- private int mGravity; | |
- | |
- private boolean mDisableChildrenWhenDisabled; | |
- | |
- private Rect mTempRect = new Rect(); | |
- | |
- private final TintManager mTintManager; | |
- | |
- /** | |
- * Construct a new spinner with the given context's theme. | |
- * | |
- * @param context The Context the view is running in, through which it can access the current | |
- * theme, resources, etc. | |
- */ | |
- SpinnerCompat(Context context) { | |
- this(context, null); | |
- } | |
- | |
- /** | |
- * Construct a new spinner with the given context's theme and the supplied mode of displaying | |
- * choices. <code>mode</code> may be one of {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}. | |
- * | |
- * @param context The Context the view is running in, through which it can access the current | |
- * theme, resources, etc. | |
- * @param mode Constant describing how the user will select choices from the spinner. | |
- * @see #MODE_DIALOG | |
- * @see #MODE_DROPDOWN | |
- */ | |
- SpinnerCompat(Context context, int mode) { | |
- this(context, null, R.attr.spinnerStyle, mode); | |
- } | |
- | |
- /** | |
- * Construct a new spinner with the given context's theme and the supplied attribute set. | |
- * | |
- * @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. | |
- */ | |
- SpinnerCompat(Context context, AttributeSet attrs) { | |
- this(context, attrs, R.attr.spinnerStyle); | |
- } | |
- | |
- /** | |
- * 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. | |
- */ | |
- SpinnerCompat(Context context, AttributeSet attrs, int defStyle) { | |
- this(context, attrs, defStyle, MODE_THEME); | |
- } | |
- | |
- /** | |
- * Construct a new spinner with the given context's theme, the supplied attribute set, and | |
- * default style. <code>mode</code> may be one of {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN} | |
- * and determines how the user will select choices from the spinner. | |
- * | |
- * @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. | |
- * @param mode Constant describing how the user will select choices from the spinner. | |
- * @see #MODE_DIALOG | |
- * @see #MODE_DROPDOWN | |
- */ | |
- SpinnerCompat(Context context, AttributeSet attrs, int defStyle, int mode) { | |
- super(context, attrs, defStyle); | |
- | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs, | |
- R.styleable.Spinner, defStyle, 0); | |
- | |
- // Need to reset this for tinting purposes | |
- if (a.hasValue(R.styleable.Spinner_android_background)) { | |
- setBackgroundDrawable(a.getDrawable(R.styleable.Spinner_android_background)); | |
- } | |
- | |
- if (mode == MODE_THEME) { | |
- mode = a.getInt(R.styleable.Spinner_spinnerMode, MODE_DIALOG); | |
- } | |
- | |
- switch (mode) { | |
- case MODE_DIALOG: { | |
- mPopup = new DialogPopup(); | |
- break; | |
- } | |
- | |
- case MODE_DROPDOWN: { | |
- final DropdownPopup popup = new DropdownPopup(context, attrs, defStyle); | |
- | |
- mDropDownWidth = a.getLayoutDimension(R.styleable.Spinner_android_dropDownWidth, | |
- ViewGroup.LayoutParams.WRAP_CONTENT); | |
- | |
- popup.setBackgroundDrawable( | |
- a.getDrawable(R.styleable.Spinner_android_popupBackground)); | |
- | |
- mPopup = popup; | |
- mForwardingListener = new ListPopupWindow.ForwardingListener(this) { | |
- @Override | |
- public ListPopupWindow getPopup() { | |
- return popup; | |
- } | |
- | |
- @Override | |
- public boolean onForwardingStarted() { | |
- if (!mPopup.isShowing()) { | |
- mPopup.show(); | |
- } | |
- return true; | |
- } | |
- }; | |
- break; | |
- } | |
- } | |
- | |
- mGravity = a.getInt(R.styleable.Spinner_android_gravity, Gravity.CENTER); | |
- | |
- mPopup.setPromptText(a.getString(R.styleable.Spinner_prompt)); | |
- | |
- mDisableChildrenWhenDisabled = a.getBoolean( | |
- R.styleable.Spinner_disableChildrenWhenDisabled, false); | |
- | |
- 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; | |
- } | |
- | |
- // Keep the TintManager in case we need it later | |
- mTintManager = a.getTintManager(); | |
- } | |
- | |
- /** | |
- * Set the background drawable for the spinner's popup window of choices. Only valid in {@link | |
- * #MODE_DROPDOWN}; this method is a no-op in other modes. | |
- * | |
- * @param background Background drawable | |
- */ | |
- public void setPopupBackgroundDrawable(Drawable background) { | |
- if (!(mPopup instanceof DropdownPopup)) { | |
- Log.e(TAG, "setPopupBackgroundDrawable: incompatible spinner mode; ignoring..."); | |
- return; | |
- } | |
- ((DropdownPopup) mPopup).setBackgroundDrawable(background); | |
- } | |
- | |
- /** | |
- * Set the background drawable for the spinner's popup window of choices. Only valid in {@link | |
- * #MODE_DROPDOWN}; this method is a no-op in other modes. | |
- * | |
- * @param resId Resource ID of a background drawable | |
- */ | |
- public void setPopupBackgroundResource(int resId) { | |
- setPopupBackgroundDrawable(mTintManager.getDrawable(resId)); | |
- } | |
- | |
- /** | |
- * Get the background drawable for the spinner's popup window of choices. Only valid in {@link | |
- * #MODE_DROPDOWN}; other modes will return null. | |
- * | |
- * @return background Background drawable | |
- */ | |
- public Drawable getPopupBackground() { | |
- return mPopup.getBackground(); | |
- } | |
- | |
- /** | |
- * Set a vertical offset in pixels for the spinner's popup window of choices. Only valid in | |
- * {@link #MODE_DROPDOWN}; this method is a no-op in other modes. | |
- * | |
- * @param pixels Vertical offset in pixels | |
- */ | |
- public void setDropDownVerticalOffset(int pixels) { | |
- mPopup.setVerticalOffset(pixels); | |
- } | |
- | |
- /** | |
- * Get the configured vertical offset in pixels for the spinner's popup window of choices. Only | |
- * valid in {@link #MODE_DROPDOWN}; other modes will return 0. | |
- * | |
- * @return Vertical offset in pixels | |
- */ | |
- public int getDropDownVerticalOffset() { | |
- return mPopup.getVerticalOffset(); | |
- } | |
- | |
- /** | |
- * Set a horizontal offset in pixels for the spinner's popup window of choices. Only valid in | |
- * {@link #MODE_DROPDOWN}; this method is a no-op in other modes. | |
- * | |
- * @param pixels Horizontal offset in pixels | |
- */ | |
- public void setDropDownHorizontalOffset(int pixels) { | |
- mPopup.setHorizontalOffset(pixels); | |
- } | |
- | |
- /** | |
- * Get the configured horizontal offset in pixels for the spinner's popup window of choices. | |
- * Only valid in {@link #MODE_DROPDOWN}; other modes will return 0. | |
- * | |
- * @return Horizontal offset in pixels | |
- */ | |
- public int getDropDownHorizontalOffset() { | |
- return mPopup.getHorizontalOffset(); | |
- } | |
- | |
- /** | |
- * Set the width of the spinner's popup window of choices in pixels. This value may also be set | |
- * to {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} to match the width of the Spinner | |
- * itself, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} to wrap to the measured | |
- * size of contained dropdown list items. | |
- * | |
- * <p>Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.</p> | |
- * | |
- * @param pixels Width in pixels, WRAP_CONTENT, or MATCH_PARENT | |
- */ | |
- public void setDropDownWidth(int pixels) { | |
- if (!(mPopup instanceof DropdownPopup)) { | |
- Log.e(TAG, "Cannot set dropdown width for MODE_DIALOG, ignoring"); | |
- return; | |
- } | |
- mDropDownWidth = pixels; | |
- } | |
- | |
- /** | |
- * Get the configured width of the spinner's popup window of choices in pixels. The returned | |
- * value may also be {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} meaning the popup | |
- * window will match the width of the Spinner itself, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} | |
- * to wrap to the measured size of contained dropdown list items. | |
- * | |
- * @return Width in pixels, WRAP_CONTENT, or MATCH_PARENT | |
- */ | |
- public int getDropDownWidth() { | |
- return mDropDownWidth; | |
- } | |
- | |
- @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} | |
- */ | |
- public void setGravity(int gravity) { | |
- if (mGravity != gravity) { | |
- if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { | |
- gravity |= GravityCompat.START; | |
- } | |
- mGravity = gravity; | |
- requestLayout(); | |
- } | |
- } | |
- | |
- @Override | |
- public void setAdapter(SpinnerAdapter adapter) { | |
- super.setAdapter(adapter); | |
- | |
- mRecycler.clear(); | |
- | |
- final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; | |
- if (targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP | |
- && adapter != null && adapter.getViewTypeCount() != 1) { | |
- throw new IllegalArgumentException("Spinner adapter view type count must be 1"); | |
- } | |
- 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 = makeView(0, false); | |
- mRecycler.put(0, child); | |
- } | |
- | |
- 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."); | |
- } | |
- | |
- void setOnItemClickListenerInt(OnItemClickListener l) { | |
- super.setOnItemClickListener(l); | |
- } | |
- | |
- @Override | |
- public boolean onTouchEvent(MotionEvent event) { | |
- if (mForwardingListener != null && mForwardingListener.onTouch(this, event)) { | |
- return true; | |
- } | |
- | |
- return super.onTouchEvent(event); | |
- } | |
- | |
- @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 means 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; | |
- if (mAdapter != null) { | |
- View sel = makeView(mSelectedPosition, true); | |
- int width = sel.getMeasuredWidth(); | |
- int selectedOffset = childrenLeft; | |
- final int layoutDirection = ViewCompat.getLayoutDirection(this); | |
- final int absoluteGravity = GravityCompat.getAbsoluteGravity(mGravity, layoutDirection); | |
- switch (absoluteGravity & 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 | |
- * @param addChild true to add the child to the spinner, false to obtain and configure only. | |
- * @return A view for the given position | |
- */ | |
- private View makeView(int position, boolean addChild) { | |
- | |
- View child; | |
- | |
- if (!mDataChanged) { | |
- child = mRecycler.get(position); | |
- if (child != null) { | |
- // Position the view | |
- setUpChild(child, addChild); | |
- | |
- return child; | |
- } | |
- } | |
- | |
- // Nothing found in the recycler -- ask the adapter for a view | |
- child = mAdapter.getView(position, null, this); | |
- | |
- // Position the view | |
- setUpChild(child, addChild); | |
- | |
- return child; | |
- } | |
- | |
- /** | |
- * Helper for makeAndAddView to set the position of a view and fill out its layout paramters. | |
- * | |
- * @param child The view to position | |
- * @param addChild true if the child should be added to the Spinner during setup | |
- */ | |
- private void setUpChild(View child, boolean addChild) { | |
- | |
- // Respect layout params that are already in the view. Otherwise | |
- // make some up... | |
- ViewGroup.LayoutParams lp = child.getLayoutParams(); | |
- if (lp == null) { | |
- lp = generateDefaultLayoutParams(); | |
- } | |
- | |
- if (addChild) { | |
- 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; | |
- } | |
- | |
- @Override | |
- public Parcelable onSaveInstanceState() { | |
- final SavedState ss = new SavedState(super.onSaveInstanceState()); | |
- ss.showDropdown = mPopup != null && mPopup.isShowing(); | |
- return ss; | |
- } | |
- | |
- @Override | |
- public void onRestoreInstanceState(Parcelable state) { | |
- SavedState ss = (SavedState) state; | |
- | |
- super.onRestoreInstanceState(ss.getSuperState()); | |
- | |
- if (ss.showDropdown) { | |
- ViewTreeObserver vto = getViewTreeObserver(); | |
- if (vto != null) { | |
- final ViewTreeObserver.OnGlobalLayoutListener listener | |
- = new ViewTreeObserver.OnGlobalLayoutListener() { | |
- @Override | |
- public void onGlobalLayout() { | |
- if (!mPopup.isShowing()) { | |
- mPopup.show(); | |
- } | |
- final ViewTreeObserver vto = getViewTreeObserver(); | |
- if (vto != null) { | |
- vto.removeGlobalOnLayoutListener(this); | |
- } | |
- } | |
- }; | |
- vto.addOnGlobalLayoutListener(listener); | |
- } | |
- } | |
- } | |
- | |
- static class SavedState extends AbsSpinnerCompat.SavedState { | |
- | |
- boolean showDropdown; | |
- | |
- SavedState(Parcelable superState) { | |
- super(superState); | |
- } | |
- | |
- private SavedState(Parcel in) { | |
- super(in); | |
- showDropdown = in.readByte() != 0; | |
- } | |
- | |
- @Override | |
- public void writeToParcel(Parcel out, int flags) { | |
- super.writeToParcel(out, flags); | |
- out.writeByte((byte) (showDropdown ? 1 : 0)); | |
- } | |
- | |
- 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]; | |
- } | |
- }; | |
- } | |
- | |
- /** | |
- * <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(); | |
- | |
- public void setBackgroundDrawable(Drawable bg); | |
- | |
- public void setVerticalOffset(int px); | |
- | |
- public void setHorizontalOffset(int px); | |
- | |
- public Drawable getBackground(); | |
- | |
- public int getVerticalOffset(); | |
- | |
- public int getHorizontalOffset(); | |
- } | |
- | |
- private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener { | |
- | |
- private AlertDialog mPopup; | |
- | |
- private ListAdapter mListAdapter; | |
- | |
- private CharSequence mPrompt; | |
- | |
- public void dismiss() { | |
- if (mPopup != null) { | |
- 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() { | |
- if (mListAdapter == null) { | |
- return; | |
- } | |
- AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); | |
- if (mPrompt != null) { | |
- builder.setTitle(mPrompt); | |
- } | |
- mPopup = builder.setSingleChoiceItems(mListAdapter, | |
- getSelectedItemPosition(), this).create(); | |
- mPopup.show(); | |
- } | |
- | |
- public void onClick(DialogInterface dialog, int which) { | |
- setSelection(which); | |
- if (mOnItemClickListener != null) { | |
- performItemClick(null, which, mListAdapter.getItemId(which)); | |
- } | |
- dismiss(); | |
- } | |
- | |
- @Override | |
- public void setBackgroundDrawable(Drawable bg) { | |
- Log.e(TAG, "Cannot set popup background for MODE_DIALOG, ignoring"); | |
- } | |
- | |
- @Override | |
- public void setVerticalOffset(int px) { | |
- Log.e(TAG, "Cannot set vertical offset for MODE_DIALOG, ignoring"); | |
- } | |
- | |
- @Override | |
- public void setHorizontalOffset(int px) { | |
- Log.e(TAG, "Cannot set horizontal offset for MODE_DIALOG, ignoring"); | |
- } | |
- | |
- @Override | |
- public Drawable getBackground() { | |
- return null; | |
- } | |
- | |
- @Override | |
- public int getVerticalOffset() { | |
- return 0; | |
- } | |
- | |
- @Override | |
- public int getHorizontalOffset() { | |
- return 0; | |
- } | |
- } | |
- | |
- private class DropdownPopup extends ListPopupWindow implements SpinnerPopup { | |
- | |
- private CharSequence mHintText; | |
- | |
- private ListAdapter mAdapter; | |
- | |
- public DropdownPopup( | |
- Context context, AttributeSet attrs, int defStyleAttr) { | |
- super(context, attrs, defStyleAttr); | |
- | |
- setAnchorView(SpinnerCompat.this); | |
- setModal(true); | |
- setPromptPosition(POSITION_PROMPT_ABOVE); | |
- | |
- setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
- @Override | |
- public void onItemClick(AdapterView<?> parent, View v, int position, long id) { | |
- SpinnerCompat.this.setSelection(position); | |
- if (mOnItemClickListener != null) { | |
- SpinnerCompat.this | |
- .performItemClick(v, position, mAdapter.getItemId(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; | |
- } | |
- | |
- void computeContentWidth() { | |
- final Drawable background = getBackground(); | |
- int hOffset = 0; | |
- if (background != null) { | |
- background.getPadding(mTempRect); | |
- hOffset = ViewUtils.isLayoutRtl(SpinnerCompat.this) ? mTempRect.right | |
- : -mTempRect.left; | |
- } else { | |
- mTempRect.left = mTempRect.right = 0; | |
- } | |
- | |
- final int spinnerPaddingLeft = SpinnerCompat.this.getPaddingLeft(); | |
- final int spinnerPaddingRight = SpinnerCompat.this.getPaddingRight(); | |
- final int spinnerWidth = SpinnerCompat.this.getWidth(); | |
- if (mDropDownWidth == WRAP_CONTENT) { | |
- int contentWidth = measureContentWidth( | |
- (SpinnerAdapter) mAdapter, getBackground()); | |
- final int contentWidthLimit = getContext().getResources() | |
- .getDisplayMetrics().widthPixels - mTempRect.left - mTempRect.right; | |
- if (contentWidth > contentWidthLimit) { | |
- contentWidth = contentWidthLimit; | |
- } | |
- setContentWidth(Math.max( | |
- contentWidth, spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight)); | |
- } else if (mDropDownWidth == MATCH_PARENT) { | |
- setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight); | |
- } else { | |
- setContentWidth(mDropDownWidth); | |
- } | |
- if (ViewUtils.isLayoutRtl(SpinnerCompat.this)) { | |
- hOffset += spinnerWidth - spinnerPaddingRight - getWidth(); | |
- } else { | |
- hOffset += spinnerPaddingLeft; | |
- } | |
- setHorizontalOffset(hOffset); | |
- } | |
- | |
- public void show(int textDirection, int textAlignment) { | |
- final boolean wasShowing = isShowing(); | |
- | |
- computeContentWidth(); | |
- setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); | |
- super.show(); | |
- final ListView listView = getListView(); | |
- listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); | |
- //listView.setTextDirection(textDirection); | |
- //listView.setTextAlignment(textAlignment); | |
- setSelection(SpinnerCompat.this.getSelectedItemPosition()); | |
- | |
- if (wasShowing) { | |
- // Skip setting up the layout/dismiss listener below. If we were previously | |
- // showing it will still stick around. | |
- return; | |
- } | |
- | |
- // Make sure we hide if our anchor goes away. | |
- // TODO: This might be appropriate to push all the way down to PopupWindow, | |
- // but it may have other side effects to investigate first. (Text editing handles, etc.) | |
- final ViewTreeObserver vto = getViewTreeObserver(); | |
- if (vto != null) { | |
- final ViewTreeObserver.OnGlobalLayoutListener layoutListener | |
- = new ViewTreeObserver.OnGlobalLayoutListener() { | |
- @Override | |
- public void onGlobalLayout() { | |
- computeContentWidth(); | |
- | |
- // Use super.show here to update; we don't want to move the selected | |
- // position or adjust other things that would be reset otherwise. | |
- DropdownPopup.super.show(); | |
- } | |
- }; | |
- vto.addOnGlobalLayoutListener(layoutListener); | |
- setOnDismissListener(new PopupWindow.OnDismissListener() { | |
- @Override | |
- public void onDismiss() { | |
- final ViewTreeObserver vto = getViewTreeObserver(); | |
- if (vto != null) { | |
- vto.removeGlobalOnLayoutListener(layoutListener); | |
- } | |
- } | |
- }); | |
- } | |
- } | |
- } | |
-} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/TintManager.java appcampat-v7-23.0.0/android/support/v7/internal/widget/TintManager.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/TintManager.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/TintManager.java 2015-07-08 08:46:10.000000000 +0900 | |
@@ -18,6 +18,7 @@ | |
import android.content.Context; | |
import android.content.res.ColorStateList; | |
+import android.graphics.Color; | |
import android.graphics.PorterDuff; | |
import android.graphics.PorterDuffColorFilter; | |
import android.graphics.drawable.Drawable; | |
@@ -90,7 +91,7 @@ | |
R.drawable.abc_textfield_activated_mtrl_alpha, | |
R.drawable.abc_textfield_search_activated_mtrl_alpha, | |
R.drawable.abc_cab_background_top_mtrl_alpha, | |
- R.drawable.abc_text_cursor_mtrl_alpha | |
+ R.drawable.abc_text_cursor_material | |
}; | |
/** | |
@@ -210,7 +211,7 @@ | |
final Context context = mContextRef.get(); | |
if (context == null) return false; | |
- PorterDuff.Mode tintMode = null; | |
+ PorterDuff.Mode tintMode = DEFAULT_MODE; | |
boolean colorAttrSet = false; | |
int colorAttr = 0; | |
int alpha = -1; | |
@@ -233,7 +234,7 @@ | |
if (colorAttrSet) { | |
final int color = getThemeAttrColor(context, colorAttr); | |
- setPorterDuffColorFilter(drawable, color, tintMode); | |
+ drawable.setColorFilter(getPorterDuffColorFilter(color, tintMode)); | |
if (alpha != -1) { | |
drawable.setAlpha(alpha); | |
@@ -294,7 +295,9 @@ | |
tint = createSwitchThumbColorStateList(context); | |
} else if (resId == R.drawable.abc_btn_default_mtrl_shape | |
|| resId == R.drawable.abc_btn_borderless_material) { | |
- tint = createButtonColorStateList(context); | |
+ tint = createDefaultButtonColorStateList(context); | |
+ } else if (resId == R.drawable.abc_btn_colored_material) { | |
+ tint = createColoredButtonColorStateList(context); | |
} else if (resId == R.drawable.abc_spinner_mtrl_am_alpha | |
|| resId == R.drawable.abc_spinner_textfield_background_material) { | |
tint = createSpinnerColorStateList(context); | |
@@ -480,12 +483,20 @@ | |
return new ColorStateList(states, colors); | |
} | |
- private ColorStateList createButtonColorStateList(Context context) { | |
+ private ColorStateList createDefaultButtonColorStateList(Context context) { | |
+ return createButtonColorStateList(context, R.attr.colorButtonNormal); | |
+ } | |
+ | |
+ private ColorStateList createColoredButtonColorStateList(Context context) { | |
+ return createButtonColorStateList(context, R.attr.colorAccent); | |
+ } | |
+ | |
+ private ColorStateList createButtonColorStateList(Context context, int baseColorAttr) { | |
final int[][] states = new int[4][]; | |
final int[] colors = new int[4]; | |
int i = 0; | |
- final int colorButtonNormal = getThemeAttrColor(context, R.attr.colorButtonNormal); | |
+ final int baseColor = getThemeAttrColor(context, baseColorAttr); | |
final int colorControlHighlight = getThemeAttrColor(context, R.attr.colorControlHighlight); | |
// Disabled state | |
@@ -494,16 +505,16 @@ | |
i++; | |
states[i] = ThemeUtils.PRESSED_STATE_SET; | |
- colors[i] = ColorUtils.compositeColors(colorControlHighlight, colorButtonNormal); | |
+ colors[i] = ColorUtils.compositeColors(colorControlHighlight, baseColor); | |
i++; | |
states[i] = ThemeUtils.FOCUSED_STATE_SET; | |
- colors[i] = ColorUtils.compositeColors(colorControlHighlight, colorButtonNormal); | |
+ colors[i] = ColorUtils.compositeColors(colorControlHighlight, baseColor); | |
i++; | |
// Default enabled state | |
states[i] = ThemeUtils.EMPTY_STATE_SET; | |
- colors[i] = colorButtonNormal; | |
+ colors[i] = baseColor; | |
i++; | |
return new ColorStateList(states, colors); | |
@@ -554,12 +565,11 @@ | |
public static void tintViewBackground(View view, TintInfo tint) { | |
final Drawable background = view.getBackground(); | |
- if (tint.mHasTintList) { | |
- setPorterDuffColorFilter( | |
- background, | |
- tint.mTintList.getColorForState(view.getDrawableState(), | |
- tint.mTintList.getDefaultColor()), | |
- tint.mHasTintMode ? tint.mTintMode : null); | |
+ if (tint.mHasTintList || tint.mHasTintMode) { | |
+ background.setColorFilter(createTintFilter( | |
+ tint.mHasTintList ? tint.mTintList : null, | |
+ tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE, | |
+ view.getDrawableState())); | |
} else { | |
background.clearColorFilter(); | |
} | |
@@ -571,12 +581,16 @@ | |
} | |
} | |
- private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) { | |
- if (mode == null) { | |
- // If we don't have a blending mode specified, use our default | |
- mode = DEFAULT_MODE; | |
+ private static PorterDuffColorFilter createTintFilter(ColorStateList tint, | |
+ PorterDuff.Mode tintMode, final int[] state) { | |
+ if (tint == null || tintMode == null) { | |
+ return null; | |
} | |
+ final int color = tint.getColorForState(state, Color.TRANSPARENT); | |
+ return getPorterDuffColorFilter(color, tintMode); | |
+ } | |
+ private static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) { | |
// First, lets see if the cache already contains the color filter | |
PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode); | |
@@ -586,6 +600,6 @@ | |
COLOR_FILTER_CACHE.put(color, mode, filter); | |
} | |
- d.setColorFilter(filter); | |
+ return filter; | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/internal/widget/ToolbarWidgetWrapper.java appcampat-v7-23.0.0/android/support/v7/internal/widget/ToolbarWidgetWrapper.java | |
--- appcampat-v7-22.2.1/android/support/v7/internal/widget/ToolbarWidgetWrapper.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/internal/widget/ToolbarWidgetWrapper.java 2015-06-29 08:17:36.000000000 +0900 | |
@@ -22,12 +22,14 @@ | |
import android.graphics.drawable.Drawable; | |
import android.os.Parcelable; | |
import android.support.v4.view.ViewCompat; | |
+import android.support.v4.view.ViewPropertyAnimatorCompat; | |
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.view.menu.ActionMenuItem; | |
import android.support.v7.internal.view.menu.MenuBuilder; | |
import android.support.v7.internal.view.menu.MenuPresenter; | |
import android.support.v7.widget.ActionMenuPresenter; | |
+import android.support.v7.widget.AppCompatSpinner; | |
import android.support.v7.widget.Toolbar; | |
import android.text.TextUtils; | |
import android.util.Log; | |
@@ -38,6 +40,8 @@ | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.view.Window; | |
+import android.widget.AdapterView; | |
+import android.widget.Spinner; | |
import android.widget.SpinnerAdapter; | |
/** | |
@@ -56,12 +60,14 @@ | |
private static final int AFFECTS_LOGO_MASK = | |
ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO; | |
+ // Default fade duration for fading in/out tool bar. | |
+ private static final long DEFAULT_FADE_DURATION_MS = 200; | |
private Toolbar mToolbar; | |
private int mDisplayOpts; | |
private View mTabView; | |
- private SpinnerCompat mSpinner; | |
+ private Spinner mSpinner; | |
private View mCustomView; | |
private Drawable mIcon; | |
@@ -241,11 +247,6 @@ | |
} | |
@Override | |
- public boolean isSplit() { | |
- return false; | |
- } | |
- | |
- @Override | |
public boolean hasExpandedActionView() { | |
return mToolbar.hasExpandedActionView(); | |
} | |
@@ -310,27 +311,6 @@ | |
} | |
@Override | |
- public boolean canSplit() { | |
- return false; | |
- } | |
- | |
- @Override | |
- public void setSplitView(ViewGroup splitView) { | |
- } | |
- | |
- @Override | |
- public void setSplitToolbar(boolean split) { | |
- if (split) { | |
- throw new UnsupportedOperationException("Cannot split an android.widget.Toolbar"); | |
- } | |
- } | |
- | |
- @Override | |
- public void setSplitWhenNarrow(boolean splitWhenNarrow) { | |
- // Ignore. | |
- } | |
- | |
- @Override | |
public boolean hasIcon() { | |
return mIcon != null; | |
} | |
@@ -547,7 +527,7 @@ | |
private void ensureSpinner() { | |
if (mSpinner == null) { | |
- mSpinner = new SpinnerCompat(getContext(), null, R.attr.actionDropDownStyle); | |
+ mSpinner = new AppCompatSpinner(getContext(), null, R.attr.actionDropDownStyle); | |
Toolbar.LayoutParams lp = new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, | |
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL); | |
mSpinner.setLayoutParams(lp); | |
@@ -556,7 +536,7 @@ | |
@Override | |
public void setDropdownParams(SpinnerAdapter adapter, | |
- AdapterViewCompat.OnItemSelectedListener listener) { | |
+ AdapterView.OnItemSelectedListener listener) { | |
ensureSpinner(); | |
mSpinner.setAdapter(adapter); | |
mSpinner.setOnItemSelectedListener(listener); | |
@@ -599,31 +579,45 @@ | |
@Override | |
public void animateToVisibility(int visibility) { | |
+ ViewPropertyAnimatorCompat anim = setupAnimatorToVisibility(visibility, | |
+ DEFAULT_FADE_DURATION_MS); | |
+ if (anim != null) { | |
+ anim.start(); | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration) { | |
if (visibility == View.GONE) { | |
- ViewCompat.animate(mToolbar).alpha(0) | |
- .setListener(new ViewPropertyAnimatorListenerAdapter() { | |
- private boolean mCanceled = false; | |
- @Override | |
- public void onAnimationEnd(View view) { | |
- if (!mCanceled) { | |
- mToolbar.setVisibility(View.GONE); | |
- } | |
- } | |
- | |
- @Override | |
- public void onAnimationCancel(View view) { | |
- mCanceled = true; | |
- } | |
- }); | |
+ ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(0f); | |
+ anim.setDuration(duration); | |
+ anim.setListener(new ViewPropertyAnimatorListenerAdapter() { | |
+ private boolean mCanceled = false; | |
+ @Override | |
+ public void onAnimationEnd(View view) { | |
+ if (!mCanceled) { | |
+ mToolbar.setVisibility(View.GONE); | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public void onAnimationCancel(View view) { | |
+ mCanceled = true; | |
+ } | |
+ }); | |
+ return anim; | |
} else if (visibility == View.VISIBLE) { | |
- ViewCompat.animate(mToolbar).alpha(1) | |
- .setListener(new ViewPropertyAnimatorListenerAdapter() { | |
- @Override | |
- public void onAnimationStart(View view) { | |
- mToolbar.setVisibility(View.VISIBLE); | |
- } | |
- }); | |
+ ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(1f); | |
+ anim.setDuration(duration); | |
+ anim.setListener(new ViewPropertyAnimatorListenerAdapter() { | |
+ @Override | |
+ public void onAnimationStart(View view) { | |
+ mToolbar.setVisibility(View.VISIBLE); | |
+ } | |
+ }); | |
+ return anim; | |
} | |
+ return null; | |
} | |
@Override | |
@@ -708,9 +702,4 @@ | |
return mToolbar.getMenu(); | |
} | |
- @Override | |
- public int getPopupTheme() { | |
- return mToolbar.getPopupTheme(); | |
- } | |
- | |
} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/ActionMenuPresenter.java appcampat-v7-23.0.0/android/support/v7/widget/ActionMenuPresenter.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/ActionMenuPresenter.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/ActionMenuPresenter.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -55,7 +55,9 @@ | |
private static final String TAG = "ActionMenuPresenter"; | |
- private View mOverflowButton; | |
+ private OverflowMenuButton mOverflowButton; | |
+ private Drawable mPendingOverflowIcon; | |
+ private boolean mPendingOverflowIconSet; | |
private boolean mReserveOverflow; | |
private boolean mReserveOverflowSet; | |
private int mWidthLimit; | |
@@ -110,6 +112,11 @@ | |
if (mReserveOverflow) { | |
if (mOverflowButton == null) { | |
mOverflowButton = new OverflowMenuButton(mSystemContext); | |
+ if (mPendingOverflowIconSet) { | |
+ mOverflowButton.setImageDrawable(mPendingOverflowIcon); | |
+ mPendingOverflowIcon = null; | |
+ mPendingOverflowIconSet = false; | |
+ } | |
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); | |
mOverflowButton.measure(spec, spec); | |
} | |
@@ -156,6 +163,24 @@ | |
mExpandedActionViewsExclusive = isExclusive; | |
} | |
+ public void setOverflowIcon(Drawable icon) { | |
+ if (mOverflowButton != null) { | |
+ mOverflowButton.setImageDrawable(icon); | |
+ } else { | |
+ mPendingOverflowIconSet = true; | |
+ mPendingOverflowIcon = icon; | |
+ } | |
+ } | |
+ | |
+ public Drawable getOverflowIcon() { | |
+ if (mOverflowButton != null) { | |
+ return mOverflowButton.getDrawable(); | |
+ } else if (mPendingOverflowIconSet) { | |
+ return mPendingOverflowIcon; | |
+ } | |
+ return null; | |
+ } | |
+ | |
@Override | |
public MenuView getMenuView(ViewGroup root) { | |
MenuView result = super.getMenuView(root); | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/ActionMenuView.java appcampat-v7-23.0.0/android/support/v7/widget/ActionMenuView.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/ActionMenuView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/ActionMenuView.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -17,7 +17,10 @@ | |
import android.content.Context; | |
import android.content.res.Configuration; | |
+import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
+import android.support.annotation.Nullable; | |
+import android.support.annotation.StyleRes; | |
import android.support.v7.internal.view.menu.ActionMenuItemView; | |
import android.support.v7.internal.view.menu.MenuBuilder; | |
import android.support.v7.internal.view.menu.MenuItemImpl; | |
@@ -50,8 +53,6 @@ | |
private MenuBuilder mMenu; | |
- private Context mContext; | |
- | |
/** Context against which to inflate popup menus. */ | |
private Context mPopupContext; | |
@@ -75,7 +76,6 @@ | |
public ActionMenuView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
- mContext = context; | |
setBaselineAligned(false); | |
final float density = context.getResources().getDisplayMetrics().density; | |
mMinCellSize = (int) (MIN_CELL_SIZE * density); | |
@@ -91,13 +91,13 @@ | |
* @param resId theme used to inflate popup menus | |
* @see #getPopupTheme() | |
*/ | |
- public void setPopupTheme(int resId) { | |
+ public void setPopupTheme(@StyleRes int resId) { | |
if (mPopupTheme != resId) { | |
mPopupTheme = resId; | |
if (resId == 0) { | |
- mPopupContext = mContext; | |
+ mPopupContext = getContext(); | |
} else { | |
- mPopupContext = new ContextThemeWrapper(mContext, resId); | |
+ mPopupContext = new ContextThemeWrapper(getContext(), resId); | |
} | |
} | |
} | |
@@ -544,6 +544,27 @@ | |
dismissPopupMenus(); | |
} | |
+ /** | |
+ * Set the icon to use for the overflow button. | |
+ * | |
+ * @param icon Drawable to set, may be null to clear the icon | |
+ */ | |
+ public void setOverflowIcon(@Nullable Drawable icon) { | |
+ getMenu(); | |
+ mPresenter.setOverflowIcon(icon); | |
+ } | |
+ | |
+ /** | |
+ * Return the current drawable used as the overflow icon. | |
+ * | |
+ * @return The overflow icon drawable | |
+ */ | |
+ @Nullable | |
+ public Drawable getOverflowIcon() { | |
+ getMenu(); | |
+ return mPresenter.getOverflowIcon(); | |
+ } | |
+ | |
/** @hide */ | |
public boolean isOverflowReserved() { | |
return mReserveOverflow; | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatAutoCompleteTextView.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatAutoCompleteTextView.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatAutoCompleteTextView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatAutoCompleteTextView.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -20,33 +20,41 @@ | |
import android.content.res.ColorStateList; | |
import android.graphics.PorterDuff; | |
import android.graphics.drawable.Drawable; | |
+import android.support.annotation.DrawableRes; | |
import android.support.annotation.Nullable; | |
import android.support.v4.view.TintableBackgroundView; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.widget.TintContextWrapper; | |
-import android.support.v7.internal.widget.TintInfo; | |
import android.support.v7.internal.widget.TintManager; | |
import android.support.v7.internal.widget.TintTypedArray; | |
import android.util.AttributeSet; | |
import android.widget.AutoCompleteTextView; | |
/** | |
- * A tint aware {@link android.widget.AutoCompleteTextView}. | |
- * <p> | |
- * This will automatically be used when you use {@link AutoCompleteTextView} in your layouts. You | |
- * should only need to manually use this class writing custom views. | |
+ * A {@link AutoCompleteTextView} which supports compatible features on older version of the | |
+ * platform, including: | |
+ * <ul> | |
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to | |
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li> | |
+ * <li>Allows dynamic tint of it background via the background tint methods in | |
+ * {@link android.support.v4.view.ViewCompat}.</li> | |
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and | |
+ * {@link R.attr#backgroundTintMode}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link AutoCompleteTextView} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatAutoCompleteTextView extends AutoCompleteTextView implements | |
TintableBackgroundView { | |
private static final int[] TINT_ATTRS = { | |
- android.R.attr.background, | |
android.R.attr.popupBackground | |
}; | |
- private TintInfo mInternalBackgroundTint; | |
- private TintInfo mBackgroundTint; | |
private TintManager mTintManager; | |
+ private AppCompatBackgroundHelper mBackgroundTintHelper; | |
+ private AppCompatTextHelper mTextHelper; | |
public AppCompatAutoCompleteTextView(Context context) { | |
this(context, null); | |
@@ -59,59 +67,57 @@ | |
public AppCompatAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(TintContextWrapper.wrap(context), attrs, defStyleAttr); | |
- if (TintManager.SHOULD_BE_USED) { | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
- TINT_ATTRS, defStyleAttr, 0); | |
- mTintManager = a.getTintManager(); | |
- | |
- if (a.hasValue(0)) { | |
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1)); | |
- if (tint != null) { | |
- setInternalBackgroundTint(tint); | |
- } | |
- } | |
- if (a.hasValue(1)) { | |
- setDropDownBackgroundDrawable(a.getDrawable(1)); | |
- } | |
- a.recycle(); | |
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
+ TINT_ATTRS, defStyleAttr, 0); | |
+ mTintManager = a.getTintManager(); | |
+ if (a.hasValue(0)) { | |
+ setDropDownBackgroundDrawable(a.getDrawable(0)); | |
} | |
+ a.recycle(); | |
+ | |
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager); | |
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); | |
+ | |
+ mTextHelper = new AppCompatTextHelper(this); | |
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr); | |
} | |
@Override | |
- public void setBackgroundResource(int resId) { | |
- super.setBackgroundResource(resId); | |
- // Update the default background tint | |
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null); | |
+ public void setDropDownBackgroundResource(@DrawableRes int resId) { | |
+ if (mTintManager != null) { | |
+ setDropDownBackgroundDrawable(mTintManager.getDrawable(resId)); | |
+ } else { | |
+ super.setDropDownBackgroundResource(resId); | |
+ } | |
} | |
@Override | |
- public void setBackgroundDrawable(Drawable background) { | |
- super.setBackgroundDrawable(background); | |
- // We don't know that this drawable is, so we need to clear the default background tint | |
- setInternalBackgroundTint(null); | |
+ public void setBackgroundResource(@DrawableRes int resId) { | |
+ super.setBackgroundResource(resId); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundResource(resId); | |
+ } | |
} | |
@Override | |
- public void setDropDownBackgroundResource(int id) { | |
- setDropDownBackgroundDrawable(mTintManager.getDrawable(id)); | |
+ public void setBackgroundDrawable(Drawable background) { | |
+ super.setBackgroundDrawable(background); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundDrawable(background); | |
+ } | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, | |
- * android.content.res.ColorStateList)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint); | |
} | |
- mBackgroundTint.mTintList = tint; | |
- mBackgroundTint.mHasTintList = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -123,24 +129,21 @@ | |
@Override | |
@Nullable | |
public ColorStateList getSupportBackgroundTintList() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); | |
} | |
- mBackgroundTint.mTintMode = tintMode; | |
- mBackgroundTint.mHasTintMode = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -152,35 +155,23 @@ | |
@Override | |
@Nullable | |
public PorterDuff.Mode getSupportBackgroundTintMode() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; | |
} | |
@Override | |
protected void drawableStateChanged() { | |
super.drawableStateChanged(); | |
- applySupportBackgroundTint(); | |
- } | |
- | |
- private void applySupportBackgroundTint() { | |
- if (getBackground() != null) { | |
- if (mBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mBackgroundTint); | |
- } else if (mInternalBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mInternalBackgroundTint); | |
- } | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.applySupportBackgroundTint(); | |
} | |
} | |
- private void setInternalBackgroundTint(ColorStateList tint) { | |
- if (tint != null) { | |
- if (mInternalBackgroundTint == null) { | |
- mInternalBackgroundTint = new TintInfo(); | |
- } | |
- mInternalBackgroundTint.mTintList = tint; | |
- mInternalBackgroundTint.mHasTintList = true; | |
- } else { | |
- mInternalBackgroundTint = null; | |
+ @Override | |
+ public void setTextAppearance(Context context, int resId) { | |
+ super.setTextAppearance(context, resId); | |
+ if (mTextHelper != null) { | |
+ mTextHelper.onSetTextAppearance(context, resId); | |
} | |
- applySupportBackgroundTint(); | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatBackgroundHelper.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatBackgroundHelper.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatBackgroundHelper.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatBackgroundHelper.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -0,0 +1,130 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.widget; | |
+ | |
+import android.content.res.ColorStateList; | |
+import android.content.res.TypedArray; | |
+import android.graphics.PorterDuff; | |
+import android.graphics.drawable.Drawable; | |
+import android.support.v4.view.ViewCompat; | |
+import android.support.v7.appcompat.R; | |
+import android.support.v7.graphics.drawable.DrawableUtils; | |
+import android.support.v7.internal.widget.TintInfo; | |
+import android.support.v7.internal.widget.TintManager; | |
+import android.util.AttributeSet; | |
+import android.view.View; | |
+ | |
+class AppCompatBackgroundHelper { | |
+ | |
+ private final View mView; | |
+ private final TintManager mTintManager; | |
+ | |
+ private TintInfo mInternalBackgroundTint; | |
+ private TintInfo mBackgroundTint; | |
+ | |
+ AppCompatBackgroundHelper(View view, TintManager tintManager) { | |
+ mView = view; | |
+ mTintManager = tintManager; | |
+ } | |
+ | |
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { | |
+ TypedArray a = mView.getContext().obtainStyledAttributes(attrs, | |
+ R.styleable.ViewBackgroundHelper, defStyleAttr, 0); | |
+ try { | |
+ if (a.hasValue(R.styleable.ViewBackgroundHelper_android_background)) { | |
+ ColorStateList tint = mTintManager.getTintList( | |
+ a.getResourceId(R.styleable.ViewBackgroundHelper_android_background, -1)); | |
+ if (tint != null) { | |
+ setInternalBackgroundTint(tint); | |
+ } | |
+ } | |
+ if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTint)) { | |
+ ViewCompat.setBackgroundTintList(mView, | |
+ a.getColorStateList(R.styleable.ViewBackgroundHelper_backgroundTint)); | |
+ } | |
+ if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTintMode)) { | |
+ ViewCompat.setBackgroundTintMode(mView, | |
+ DrawableUtils.parseTintMode( | |
+ a.getInt(R.styleable.ViewBackgroundHelper_backgroundTintMode, -1), | |
+ null)); | |
+ } | |
+ } finally { | |
+ a.recycle(); | |
+ } | |
+ } | |
+ | |
+ void onSetBackgroundResource(int resId) { | |
+ // Update the default background tint | |
+ setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null); | |
+ } | |
+ | |
+ void onSetBackgroundDrawable(Drawable background) { | |
+ // We don't know that this drawable is, so we need to clear the default background tint | |
+ setInternalBackgroundTint(null); | |
+ } | |
+ | |
+ void setSupportBackgroundTintList(ColorStateList tint) { | |
+ if (mBackgroundTint == null) { | |
+ mBackgroundTint = new TintInfo(); | |
+ } | |
+ mBackgroundTint.mTintList = tint; | |
+ mBackgroundTint.mHasTintList = true; | |
+ | |
+ applySupportBackgroundTint(); | |
+ } | |
+ | |
+ ColorStateList getSupportBackgroundTintList() { | |
+ return mBackgroundTint != null ? mBackgroundTint.mTintList : null; | |
+ } | |
+ | |
+ void setSupportBackgroundTintMode(PorterDuff.Mode tintMode) { | |
+ if (mBackgroundTint == null) { | |
+ mBackgroundTint = new TintInfo(); | |
+ } | |
+ mBackgroundTint.mTintMode = tintMode; | |
+ mBackgroundTint.mHasTintMode = true; | |
+ | |
+ applySupportBackgroundTint(); | |
+ } | |
+ | |
+ PorterDuff.Mode getSupportBackgroundTintMode() { | |
+ return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; | |
+ } | |
+ | |
+ void applySupportBackgroundTint() { | |
+ if (mView.getBackground() != null) { | |
+ if (mBackgroundTint != null) { | |
+ TintManager.tintViewBackground(mView, mBackgroundTint); | |
+ } else if (mInternalBackgroundTint != null) { | |
+ TintManager.tintViewBackground(mView, mInternalBackgroundTint); | |
+ } | |
+ } | |
+ } | |
+ | |
+ void setInternalBackgroundTint(ColorStateList tint) { | |
+ if (tint != null) { | |
+ if (mInternalBackgroundTint == null) { | |
+ mInternalBackgroundTint = new TintInfo(); | |
+ } | |
+ mInternalBackgroundTint.mTintList = tint; | |
+ mInternalBackgroundTint.mHasTintList = true; | |
+ } else { | |
+ mInternalBackgroundTint = null; | |
+ } | |
+ applySupportBackgroundTint(); | |
+ } | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatButton.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatButton.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatButton.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatButton.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -18,38 +18,39 @@ | |
import android.content.Context; | |
import android.content.res.ColorStateList; | |
-import android.content.res.TypedArray; | |
import android.graphics.PorterDuff; | |
import android.graphics.drawable.Drawable; | |
-import android.os.Build; | |
+import android.support.annotation.DrawableRes; | |
import android.support.annotation.Nullable; | |
import android.support.v4.view.TintableBackgroundView; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.text.AllCapsTransformationMethod; | |
-import android.support.v7.internal.widget.ThemeUtils; | |
-import android.support.v7.internal.widget.TintInfo; | |
import android.support.v7.internal.widget.TintManager; | |
-import android.support.v7.internal.widget.TintTypedArray; | |
import android.util.AttributeSet; | |
import android.view.accessibility.AccessibilityEvent; | |
import android.view.accessibility.AccessibilityNodeInfo; | |
import android.widget.Button; | |
/** | |
- * A tint aware {@link android.widget.Button}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.Button} in your layouts. You | |
- * should only need to manually use this class when writing custom views. | |
+ * A {@link Button} which supports compatible features on older version of the platform, | |
+ * including: | |
+ * <ul> | |
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to | |
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li> | |
+ * <li>Allows dynamic tint of it background via the background tint methods in | |
+ * {@link android.support.v4.view.ViewCompat}.</li> | |
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and | |
+ * {@link R.attr#backgroundTintMode}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link android.widget.Button} in your | |
+ * layouts. You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatButton extends Button implements TintableBackgroundView { | |
- private static final int[] TINT_ATTRS = { | |
- android.R.attr.background | |
- }; | |
- | |
- private TintInfo mInternalBackgroundTint; | |
- private TintInfo mBackgroundTint; | |
- private TintManager mTintManager; | |
+ private final TintManager mTintManager; | |
+ private final AppCompatBackgroundHelper mBackgroundTintHelper; | |
+ private final AppCompatTextHelper mTextHelper; | |
public AppCompatButton(Context context) { | |
this(context, null); | |
@@ -62,95 +63,41 @@ | |
public AppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
- if (TintManager.SHOULD_BE_USED) { | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
- TINT_ATTRS, defStyleAttr, 0); | |
- if (a.hasValue(0)) { | |
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1)); | |
- if (tint != null) { | |
- setInternalBackgroundTint(tint); | |
- } | |
- } | |
- mTintManager = a.getTintManager(); | |
- a.recycle(); | |
- } | |
- | |
- // First read the TextAppearance style id | |
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView, | |
- defStyleAttr, 0); | |
- final int ap = a.getResourceId(R.styleable.AppCompatTextView_android_textAppearance, -1); | |
- a.recycle(); | |
- | |
- // Now check TextAppearance's textAllCaps value | |
- if (ap != -1) { | |
- TypedArray appearance = context.obtainStyledAttributes(ap, R.styleable.TextAppearance); | |
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) { | |
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false)); | |
- } | |
- appearance.recycle(); | |
- } | |
- | |
- // Now read the style's value | |
- a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView, defStyleAttr, 0); | |
- if (a.hasValue(R.styleable.AppCompatTextView_textAllCaps)) { | |
- setAllCaps(a.getBoolean(R.styleable.AppCompatTextView_textAllCaps, false)); | |
- } | |
- a.recycle(); | |
- | |
- final ColorStateList textColors = getTextColors(); | |
- if (textColors != null && !textColors.isStateful()) { | |
- // If we have a ColorStateList which isn't stateful, create one which includes | |
- // a disabled state | |
- | |
- final int disabledTextColor; | |
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { | |
- // Pre-Lollipop, we will use textColorSecondary with android:disabledAlpha | |
- // applied | |
- disabledTextColor = ThemeUtils.getDisabledThemeAttrColor(context, | |
- android.R.attr.textColorSecondary); | |
- } else { | |
- // With certain styles on Lollipop, there is a StateListAnimator which sets | |
- // an alpha on the whole view, so we don't need to apply disabledAlpha to | |
- // textColorSecondary | |
- disabledTextColor = ThemeUtils.getThemeAttrColor(context, | |
- android.R.attr.textColorSecondary); | |
- } | |
+ mTintManager = TintManager.get(getContext()); | |
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager); | |
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); | |
- setTextColor(ThemeUtils.createDisabledStateList( | |
- textColors.getDefaultColor(), disabledTextColor)); | |
- } | |
+ mTextHelper = new AppCompatTextHelper(this); | |
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr); | |
} | |
@Override | |
- public void setBackgroundResource(int resId) { | |
+ public void setBackgroundResource(@DrawableRes int resId) { | |
super.setBackgroundResource(resId); | |
- // Update the default background tint | |
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundResource(resId); | |
+ } | |
} | |
@Override | |
public void setBackgroundDrawable(Drawable background) { | |
super.setBackgroundDrawable(background); | |
- // We don't know that this drawable is, so we need to clear the default background tint | |
- setInternalBackgroundTint(null); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundDrawable(background); | |
+ } | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, | |
- * android.content.res.ColorStateList)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint); | |
} | |
- mBackgroundTint.mTintList = tint; | |
- mBackgroundTint.mHasTintList = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -162,24 +109,21 @@ | |
@Override | |
@Nullable | |
public ColorStateList getSupportBackgroundTintList() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); | |
} | |
- mBackgroundTint.mTintMode = tintMode; | |
- mBackgroundTint.mHasTintMode = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -191,36 +135,24 @@ | |
@Override | |
@Nullable | |
public PorterDuff.Mode getSupportBackgroundTintMode() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; | |
} | |
@Override | |
protected void drawableStateChanged() { | |
super.drawableStateChanged(); | |
- applySupportBackgroundTint(); | |
- } | |
- | |
- private void applySupportBackgroundTint() { | |
- if (getBackground() != null) { | |
- if (mBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mBackgroundTint); | |
- } else if (mInternalBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mInternalBackgroundTint); | |
- } | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.applySupportBackgroundTint(); | |
} | |
} | |
- private void setInternalBackgroundTint(ColorStateList tint) { | |
- if (tint != null) { | |
- if (mInternalBackgroundTint == null) { | |
- mInternalBackgroundTint = new TintInfo(); | |
- } | |
- mInternalBackgroundTint.mTintList = tint; | |
- mInternalBackgroundTint.mHasTintList = true; | |
- } else { | |
- mInternalBackgroundTint = null; | |
+ @Override | |
+ public void setTextAppearance(Context context, int resId) { | |
+ super.setTextAppearance(context, resId); | |
+ if (mTextHelper != null) { | |
+ mTextHelper.onSetTextAppearance(context, resId); | |
} | |
- applySupportBackgroundTint(); | |
} | |
@Override | |
@@ -235,19 +167,18 @@ | |
info.setClassName(Button.class.getName()); | |
} | |
- public void setAllCaps(boolean allCaps) { | |
- setTransformationMethod(allCaps ? new AllCapsTransformationMethod(getContext()) : null); | |
- } | |
- | |
- @Override | |
- public void setTextAppearance(Context context, int resId) { | |
- super.setTextAppearance(context, resId); | |
- | |
- TypedArray appearance = context.obtainStyledAttributes(resId, R.styleable.TextAppearance); | |
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) { | |
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false)); | |
+ /** | |
+ * Sets the properties of this field to transform input to ALL CAPS | |
+ * display. This may use a "small caps" formatting if available. | |
+ * This setting will be ignored if this field is editable or selectable. | |
+ * | |
+ * This call replaces the current transformation method. Disabling this | |
+ * will not necessarily restore the previous behavior from before this | |
+ * was enabled. | |
+ */ | |
+ public void setSupportAllCaps(boolean allCaps) { | |
+ if (mTextHelper != null) { | |
+ mTextHelper.setAllCaps(allCaps); | |
} | |
- appearance.recycle(); | |
} | |
- | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatCheckBox.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatCheckBox.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatCheckBox.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatCheckBox.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -17,29 +17,35 @@ | |
package android.support.v7.widget; | |
import android.content.Context; | |
+import android.content.res.ColorStateList; | |
+import android.graphics.PorterDuff; | |
import android.graphics.drawable.Drawable; | |
-import android.os.Build; | |
import android.support.annotation.DrawableRes; | |
+import android.support.annotation.Nullable; | |
+import android.support.v4.content.ContextCompat; | |
+import android.support.v4.widget.TintableCompoundButton; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.widget.TintManager; | |
-import android.support.v7.internal.widget.TintTypedArray; | |
import android.util.AttributeSet; | |
import android.widget.CheckBox; | |
/** | |
- * A tint aware {@link android.widget.CheckBox}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.CheckBox} in your layouts. | |
- * You should only need to manually use this class when writing custom views. | |
+ * A {@link CheckBox} which supports compatible features on older version of the platform, | |
+ * including: | |
+ * <ul> | |
+ * <li>Allows dynamic tint of it background via the background tint methods in | |
+ * {@link android.support.v4.widget.CompoundButtonCompat}.</li> | |
+ * <li>Allows setting of the background tint using {@link R.attr#buttonTint} and | |
+ * {@link R.attr#buttonTintMode}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link CheckBox} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
-public class AppCompatCheckBox extends CheckBox { | |
- | |
- private static final int[] TINT_ATTRS = { | |
- android.R.attr.button | |
- }; | |
+public class AppCompatCheckBox extends CheckBox implements TintableCompoundButton { | |
private TintManager mTintManager; | |
- private Drawable mButtonDrawable; | |
+ private AppCompatCompoundButtonHelper mCompoundButtonHelper; | |
public AppCompatCheckBox(Context context) { | |
this(context, null); | |
@@ -51,43 +57,77 @@ | |
public AppCompatCheckBox(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
- | |
- if (TintManager.SHOULD_BE_USED) { | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
- TINT_ATTRS, defStyleAttr, 0); | |
- setButtonDrawable(a.getDrawable(0)); | |
- a.recycle(); | |
- | |
- mTintManager = a.getTintManager(); | |
- } | |
+ mTintManager = TintManager.get(context); | |
+ mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager); | |
+ mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr); | |
} | |
@Override | |
public void setButtonDrawable(Drawable buttonDrawable) { | |
super.setButtonDrawable(buttonDrawable); | |
- mButtonDrawable = buttonDrawable; | |
+ if (mCompoundButtonHelper != null) { | |
+ mCompoundButtonHelper.onSetButtonDrawable(); | |
+ } | |
} | |
@Override | |
public void setButtonDrawable(@DrawableRes int resId) { | |
- if (mTintManager != null) { | |
- setButtonDrawable(mTintManager.getDrawable(resId)); | |
- } else { | |
- super.setButtonDrawable(resId); | |
- } | |
+ setButtonDrawable(mTintManager != null | |
+ ? mTintManager.getDrawable(resId) | |
+ : ContextCompat.getDrawable(getContext(), resId)); | |
} | |
@Override | |
public int getCompoundPaddingLeft() { | |
- int padding = super.getCompoundPaddingLeft(); | |
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { | |
- // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll | |
- // workaround that here | |
- if (mButtonDrawable != null) { | |
- padding += mButtonDrawable.getIntrinsicWidth(); | |
- } | |
+ final int value = super.getCompoundPaddingLeft(); | |
+ return mCompoundButtonHelper != null | |
+ ? mCompoundButtonHelper.getCompoundPaddingLeft(value) | |
+ : value; | |
+ } | |
+ | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Override | |
+ public void setSupportButtonTintList(@Nullable ColorStateList tint) { | |
+ if (mCompoundButtonHelper != null) { | |
+ mCompoundButtonHelper.setSupportButtonTintList(tint); | |
} | |
- return padding; | |
} | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Nullable | |
+ @Override | |
+ public ColorStateList getSupportButtonTintList() { | |
+ return mCompoundButtonHelper != null | |
+ ? mCompoundButtonHelper.getSupportButtonTintList() | |
+ : null; | |
+ } | |
+ | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Override | |
+ public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) { | |
+ if (mCompoundButtonHelper != null) { | |
+ mCompoundButtonHelper.setSupportButtonTintMode(tintMode); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Nullable | |
+ @Override | |
+ public PorterDuff.Mode getSupportButtonTintMode() { | |
+ return mCompoundButtonHelper != null | |
+ ? mCompoundButtonHelper.getSupportButtonTintMode() | |
+ : null; | |
+ } | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatCheckedTextView.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatCheckedTextView.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatCheckedTextView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatCheckedTextView.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -18,17 +18,16 @@ | |
import android.content.Context; | |
import android.support.annotation.DrawableRes; | |
-import android.support.v7.appcompat.R; | |
import android.support.v7.internal.widget.TintManager; | |
import android.support.v7.internal.widget.TintTypedArray; | |
import android.util.AttributeSet; | |
import android.widget.CheckedTextView; | |
/** | |
- * A tint aware {@link android.widget.CheckedTextView}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.CheckedTextView} in your | |
- * layouts. You should only need to manually use this class when writing custom views. | |
+ * A {@link CheckedTextView} which supports compatible features on older version of the platform. | |
+ * | |
+ * <p>This will automatically be used when you use {@link CheckedTextView} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatCheckedTextView extends CheckedTextView { | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatCompoundButtonHelper.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatCompoundButtonHelper.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatCompoundButtonHelper.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatCompoundButtonHelper.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -0,0 +1,147 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.widget; | |
+ | |
+import android.content.res.ColorStateList; | |
+import android.content.res.TypedArray; | |
+import android.graphics.PorterDuff; | |
+import android.graphics.drawable.Drawable; | |
+import android.os.Build; | |
+import android.support.annotation.Nullable; | |
+import android.support.v4.graphics.drawable.DrawableCompat; | |
+import android.support.v4.widget.CompoundButtonCompat; | |
+import android.support.v7.appcompat.R; | |
+import android.support.v7.graphics.drawable.DrawableUtils; | |
+import android.support.v7.internal.widget.TintManager; | |
+import android.util.AttributeSet; | |
+import android.widget.CompoundButton; | |
+ | |
+class AppCompatCompoundButtonHelper { | |
+ | |
+ private final CompoundButton mView; | |
+ private final TintManager mTintManager; | |
+ | |
+ private ColorStateList mButtonTintList = null; | |
+ private PorterDuff.Mode mButtonTintMode = null; | |
+ private boolean mHasButtonTint = false; | |
+ private boolean mHasButtonTintMode = false; | |
+ | |
+ private boolean mSkipNextApply; | |
+ | |
+ /** | |
+ * Interface which allows us to directly set a button, bypass any calls back to ourselves. | |
+ */ | |
+ interface DirectSetButtonDrawableInterface { | |
+ void setButtonDrawable(Drawable buttonDrawable); | |
+ } | |
+ | |
+ AppCompatCompoundButtonHelper(CompoundButton view, TintManager tintManager) { | |
+ mView = view; | |
+ mTintManager = tintManager; | |
+ } | |
+ | |
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { | |
+ TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.CompoundButton, | |
+ defStyleAttr, 0); | |
+ try { | |
+ if (a.hasValue(R.styleable.CompoundButton_android_button)) { | |
+ final int resourceId = a.getResourceId( | |
+ R.styleable.CompoundButton_android_button, 0); | |
+ if (resourceId != 0) { | |
+ mView.setButtonDrawable(mTintManager.getDrawable(resourceId)); | |
+ } | |
+ } | |
+ if (a.hasValue(R.styleable.CompoundButton_buttonTint)) { | |
+ CompoundButtonCompat.setButtonTintList(mView, | |
+ a.getColorStateList(R.styleable.CompoundButton_buttonTint)); | |
+ } | |
+ if (a.hasValue(R.styleable.CompoundButton_buttonTintMode)) { | |
+ CompoundButtonCompat.setButtonTintMode(mView, | |
+ DrawableUtils.parseTintMode( | |
+ a.getInt(R.styleable.CompoundButton_buttonTintMode, -1), | |
+ null)); | |
+ } | |
+ } finally { | |
+ a.recycle(); | |
+ } | |
+ } | |
+ | |
+ void setSupportButtonTintList(ColorStateList tint) { | |
+ mButtonTintList = tint; | |
+ mHasButtonTint = true; | |
+ | |
+ applyButtonTint(); | |
+ } | |
+ | |
+ ColorStateList getSupportButtonTintList() { | |
+ return mButtonTintList; | |
+ } | |
+ | |
+ void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) { | |
+ mButtonTintMode = tintMode; | |
+ mHasButtonTintMode = true; | |
+ | |
+ applyButtonTint(); | |
+ } | |
+ | |
+ PorterDuff.Mode getSupportButtonTintMode() { | |
+ return mButtonTintMode; | |
+ } | |
+ | |
+ void onSetButtonDrawable() { | |
+ if (mSkipNextApply) { | |
+ mSkipNextApply = false; | |
+ return; | |
+ } | |
+ | |
+ mSkipNextApply = true; | |
+ applyButtonTint(); | |
+ } | |
+ | |
+ void applyButtonTint() { | |
+ Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView); | |
+ | |
+ if (buttonDrawable != null && (mHasButtonTint || mHasButtonTintMode)) { | |
+ buttonDrawable = DrawableCompat.wrap(buttonDrawable); | |
+ buttonDrawable = buttonDrawable.mutate(); | |
+ if (mHasButtonTint) { | |
+ DrawableCompat.setTintList(buttonDrawable, mButtonTintList); | |
+ } | |
+ if (mHasButtonTintMode) { | |
+ DrawableCompat.setTintMode(buttonDrawable, mButtonTintMode); | |
+ } | |
+ // The drawable (or one of its children) may not have been | |
+ // stateful before applying the tint, so let's try again. | |
+ if (buttonDrawable.isStateful()) { | |
+ buttonDrawable.setState(mView.getDrawableState()); | |
+ } | |
+ mView.setButtonDrawable(buttonDrawable); | |
+ } | |
+ } | |
+ | |
+ int getCompoundPaddingLeft(int superValue) { | |
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { | |
+ // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll | |
+ // workaround that here | |
+ Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView); | |
+ if (buttonDrawable != null) { | |
+ superValue += buttonDrawable.getIntrinsicWidth(); | |
+ } | |
+ } | |
+ return superValue; | |
+ } | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatEditText.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatEditText.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatEditText.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatEditText.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -20,31 +20,35 @@ | |
import android.content.res.ColorStateList; | |
import android.graphics.PorterDuff; | |
import android.graphics.drawable.Drawable; | |
+import android.support.annotation.DrawableRes; | |
import android.support.annotation.Nullable; | |
import android.support.v4.view.TintableBackgroundView; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.widget.TintContextWrapper; | |
-import android.support.v7.internal.widget.TintInfo; | |
import android.support.v7.internal.widget.TintManager; | |
-import android.support.v7.internal.widget.TintTypedArray; | |
import android.util.AttributeSet; | |
import android.widget.EditText; | |
/** | |
- * A tint aware {@link android.widget.EditText}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.EditText} in your | |
- * layouts. You should only need to manually use this class when writing custom views. | |
+ * A {@link EditText} which supports compatible features on older version of the platform, | |
+ * including: | |
+ * <ul> | |
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to | |
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li> | |
+ * <li>Allows dynamic tint of it background via the background tint methods in | |
+ * {@link android.support.v4.view.ViewCompat}.</li> | |
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and | |
+ * {@link R.attr#backgroundTintMode}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link android.widget.EditText} in your | |
+ * layouts. You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatEditText extends EditText implements TintableBackgroundView { | |
- private static final int[] TINT_ATTRS = { | |
- android.R.attr.background | |
- }; | |
- | |
- private TintInfo mInternalBackgroundTint; | |
- private TintInfo mBackgroundTint; | |
private TintManager mTintManager; | |
+ private AppCompatBackgroundHelper mBackgroundTintHelper; | |
+ private AppCompatTextHelper mTextHelper; | |
public AppCompatEditText(Context context) { | |
this(context, null); | |
@@ -57,50 +61,41 @@ | |
public AppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(TintContextWrapper.wrap(context), attrs, defStyleAttr); | |
- if (TintManager.SHOULD_BE_USED) { | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
- TINT_ATTRS, defStyleAttr, 0); | |
- if (a.hasValue(0)) { | |
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1)); | |
- if (tint != null) { | |
- setInternalBackgroundTint(tint); | |
- } | |
- } | |
- mTintManager = a.getTintManager(); | |
- a.recycle(); | |
- } | |
+ mTintManager = TintManager.get(getContext()); | |
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager); | |
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); | |
+ | |
+ mTextHelper = new AppCompatTextHelper(this); | |
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr); | |
} | |
@Override | |
- public void setBackgroundResource(int resId) { | |
+ public void setBackgroundResource(@DrawableRes int resId) { | |
super.setBackgroundResource(resId); | |
- // Update the default background tint | |
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundResource(resId); | |
+ } | |
} | |
@Override | |
public void setBackgroundDrawable(Drawable background) { | |
super.setBackgroundDrawable(background); | |
- // We don't know that this drawable is, so we need to clear the default background tint | |
- setInternalBackgroundTint(null); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundDrawable(background); | |
+ } | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, | |
- * android.content.res.ColorStateList)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint); | |
} | |
- mBackgroundTint.mTintList = tint; | |
- mBackgroundTint.mHasTintList = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -112,24 +107,21 @@ | |
@Override | |
@Nullable | |
public ColorStateList getSupportBackgroundTintList() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); | |
} | |
- mBackgroundTint.mTintMode = tintMode; | |
- mBackgroundTint.mHasTintMode = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -141,35 +133,23 @@ | |
@Override | |
@Nullable | |
public PorterDuff.Mode getSupportBackgroundTintMode() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; | |
} | |
@Override | |
protected void drawableStateChanged() { | |
super.drawableStateChanged(); | |
- applySupportBackgroundTint(); | |
- } | |
- | |
- private void applySupportBackgroundTint() { | |
- if (getBackground() != null) { | |
- if (mBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mBackgroundTint); | |
- } else if (mInternalBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mInternalBackgroundTint); | |
- } | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.applySupportBackgroundTint(); | |
} | |
} | |
- private void setInternalBackgroundTint(ColorStateList tint) { | |
- if (tint != null) { | |
- if (mInternalBackgroundTint == null) { | |
- mInternalBackgroundTint = new TintInfo(); | |
- } | |
- mInternalBackgroundTint.mTintList = tint; | |
- mInternalBackgroundTint.mHasTintList = true; | |
- } else { | |
- mInternalBackgroundTint = null; | |
+ @Override | |
+ public void setTextAppearance(Context context, int resId) { | |
+ super.setTextAppearance(context, resId); | |
+ if (mTextHelper != null) { | |
+ mTextHelper.onSetTextAppearance(context, resId); | |
} | |
- applySupportBackgroundTint(); | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -25,29 +25,36 @@ | |
import android.support.v4.view.TintableBackgroundView; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.widget.TintContextWrapper; | |
-import android.support.v7.internal.widget.TintInfo; | |
import android.support.v7.internal.widget.TintManager; | |
import android.support.v7.internal.widget.TintTypedArray; | |
import android.util.AttributeSet; | |
import android.widget.MultiAutoCompleteTextView; | |
/** | |
- * A tint aware {@link android.widget.MultiAutoCompleteTextView}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.MultiAutoCompleteTextView} | |
- * in your layouts. You should only need to manually use this class when writing custom views. | |
+ * A {@link MultiAutoCompleteTextView} which supports compatible features on older version of the | |
+ * platform, including: | |
+ * <ul> | |
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to | |
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li> | |
+ * <li>Allows dynamic tint of it background via the background tint methods in | |
+ * {@link android.support.v4.view.ViewCompat}.</li> | |
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and | |
+ * {@link R.attr#backgroundTintMode}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link MultiAutoCompleteTextView} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatMultiAutoCompleteTextView extends MultiAutoCompleteTextView | |
implements TintableBackgroundView { | |
private static final int[] TINT_ATTRS = { | |
- android.R.attr.background, | |
android.R.attr.popupBackground | |
}; | |
- private TintInfo mInternalBackgroundTint; | |
- private TintInfo mBackgroundTint; | |
private TintManager mTintManager; | |
+ private AppCompatBackgroundHelper mBackgroundTintHelper; | |
+ private AppCompatTextHelper mTextHelper; | |
public AppCompatMultiAutoCompleteTextView(Context context) { | |
this(context, null); | |
@@ -60,63 +67,57 @@ | |
public AppCompatMultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(TintContextWrapper.wrap(context), attrs, defStyleAttr); | |
- if (TintManager.SHOULD_BE_USED) { | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
- TINT_ATTRS, defStyleAttr, 0); | |
- mTintManager = a.getTintManager(); | |
- | |
- if (a.hasValue(0)) { | |
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1)); | |
- if (tint != null) { | |
- setInternalBackgroundTint(tint); | |
- } | |
- } | |
- if (a.hasValue(1)) { | |
- setDropDownBackgroundDrawable(a.getDrawable(1)); | |
- } | |
- a.recycle(); | |
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
+ TINT_ATTRS, defStyleAttr, 0); | |
+ mTintManager = a.getTintManager(); | |
+ if (a.hasValue(0)) { | |
+ setDropDownBackgroundDrawable(a.getDrawable(0)); | |
} | |
+ a.recycle(); | |
+ | |
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager); | |
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); | |
+ | |
+ mTextHelper = new AppCompatTextHelper(this); | |
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr); | |
} | |
@Override | |
- public void setBackgroundResource(int resId) { | |
- super.setBackgroundResource(resId); | |
- // Update the default background tint | |
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null); | |
+ public void setDropDownBackgroundResource(@DrawableRes int resId) { | |
+ if (mTintManager != null) { | |
+ setDropDownBackgroundDrawable(mTintManager.getDrawable(resId)); | |
+ } else { | |
+ super.setDropDownBackgroundResource(resId); | |
+ } | |
} | |
@Override | |
- public void setBackgroundDrawable(Drawable background) { | |
- super.setBackgroundDrawable(background); | |
- // We don't know that this drawable is, so we need to clear the default background tint | |
- setInternalBackgroundTint(null); | |
+ public void setBackgroundResource(@DrawableRes int resId) { | |
+ super.setBackgroundResource(resId); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundResource(resId); | |
+ } | |
} | |
@Override | |
- public void setDropDownBackgroundResource(@DrawableRes int id) { | |
- if (mTintManager != null) { | |
- setDropDownBackgroundDrawable(mTintManager.getDrawable(id)); | |
- } else { | |
- super.setDropDownBackgroundResource(id); | |
+ public void setBackgroundDrawable(Drawable background) { | |
+ super.setBackgroundDrawable(background); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundDrawable(background); | |
} | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, | |
- * android.content.res.ColorStateList)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint); | |
} | |
- mBackgroundTint.mTintList = tint; | |
- mBackgroundTint.mHasTintList = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -128,24 +129,21 @@ | |
@Override | |
@Nullable | |
public ColorStateList getSupportBackgroundTintList() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); | |
} | |
- mBackgroundTint.mTintMode = tintMode; | |
- mBackgroundTint.mHasTintMode = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -157,35 +155,23 @@ | |
@Override | |
@Nullable | |
public PorterDuff.Mode getSupportBackgroundTintMode() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; | |
} | |
@Override | |
protected void drawableStateChanged() { | |
super.drawableStateChanged(); | |
- applySupportBackgroundTint(); | |
- } | |
- | |
- private void applySupportBackgroundTint() { | |
- if (getBackground() != null) { | |
- if (mBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mBackgroundTint); | |
- } else if (mInternalBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mInternalBackgroundTint); | |
- } | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.applySupportBackgroundTint(); | |
} | |
} | |
- private void setInternalBackgroundTint(ColorStateList tint) { | |
- if (tint != null) { | |
- if (mInternalBackgroundTint == null) { | |
- mInternalBackgroundTint = new TintInfo(); | |
- } | |
- mInternalBackgroundTint.mTintList = tint; | |
- mInternalBackgroundTint.mHasTintList = true; | |
- } else { | |
- mInternalBackgroundTint = null; | |
+ @Override | |
+ public void setTextAppearance(Context context, int resId) { | |
+ super.setTextAppearance(context, resId); | |
+ if (mTextHelper != null) { | |
+ mTextHelper.onSetTextAppearance(context, resId); | |
} | |
- applySupportBackgroundTint(); | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatRadioButton.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatRadioButton.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatRadioButton.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatRadioButton.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -17,29 +17,35 @@ | |
package android.support.v7.widget; | |
import android.content.Context; | |
+import android.content.res.ColorStateList; | |
+import android.graphics.PorterDuff; | |
import android.graphics.drawable.Drawable; | |
-import android.os.Build; | |
import android.support.annotation.DrawableRes; | |
+import android.support.annotation.Nullable; | |
+import android.support.v4.content.ContextCompat; | |
+import android.support.v4.widget.TintableCompoundButton; | |
import android.support.v7.appcompat.R; | |
import android.support.v7.internal.widget.TintManager; | |
-import android.support.v7.internal.widget.TintTypedArray; | |
import android.util.AttributeSet; | |
import android.widget.RadioButton; | |
/** | |
- * A tint aware {@link android.widget.RadioButton}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.RadioButton} in your | |
- * layouts. You should only need to manually use this class when writing custom views. | |
+ * A {@link RadioButton} which supports compatible features on older version of the platform, | |
+ * including: | |
+ * <ul> | |
+ * <li>Allows dynamic tint of it background via the background tint methods in | |
+ * {@link android.support.v4.widget.CompoundButtonCompat}.</li> | |
+ * <li>Allows setting of the background tint using {@link R.attr#buttonTint} and | |
+ * {@link R.attr#buttonTintMode}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link RadioButton} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
-public class AppCompatRadioButton extends RadioButton { | |
- | |
- private static final int[] TINT_ATTRS = { | |
- android.R.attr.button | |
- }; | |
+public class AppCompatRadioButton extends RadioButton implements TintableCompoundButton { | |
private TintManager mTintManager; | |
- private Drawable mButtonDrawable; | |
+ private AppCompatCompoundButtonHelper mCompoundButtonHelper; | |
public AppCompatRadioButton(Context context) { | |
this(context, null); | |
@@ -51,42 +57,77 @@ | |
public AppCompatRadioButton(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
- | |
- if (TintManager.SHOULD_BE_USED) { | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
- TINT_ATTRS, defStyleAttr, 0); | |
- setButtonDrawable(a.getDrawable(0)); | |
- a.recycle(); | |
- | |
- mTintManager = a.getTintManager(); | |
- } | |
+ mTintManager = TintManager.get(context); | |
+ mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager); | |
+ mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr); | |
} | |
@Override | |
public void setButtonDrawable(Drawable buttonDrawable) { | |
super.setButtonDrawable(buttonDrawable); | |
- mButtonDrawable = buttonDrawable; | |
+ if (mCompoundButtonHelper != null) { | |
+ mCompoundButtonHelper.onSetButtonDrawable(); | |
+ } | |
} | |
@Override | |
- public void setButtonDrawable(@DrawableRes int resid) { | |
- if (mTintManager != null) { | |
- setButtonDrawable(mTintManager.getDrawable(resid)); | |
- } else { | |
- super.setButtonDrawable(resid); | |
- } | |
+ public void setButtonDrawable(@DrawableRes int resId) { | |
+ setButtonDrawable(mTintManager != null | |
+ ? mTintManager.getDrawable(resId) | |
+ : ContextCompat.getDrawable(getContext(), resId)); | |
} | |
@Override | |
public int getCompoundPaddingLeft() { | |
- int padding = super.getCompoundPaddingLeft(); | |
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { | |
- // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll | |
- // workaround that here | |
- if (mButtonDrawable != null) { | |
- padding += mButtonDrawable.getIntrinsicWidth(); | |
- } | |
+ final int value = super.getCompoundPaddingLeft(); | |
+ return mCompoundButtonHelper != null | |
+ ? mCompoundButtonHelper.getCompoundPaddingLeft(value) | |
+ : value; | |
+ } | |
+ | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Override | |
+ public void setSupportButtonTintList(@Nullable ColorStateList tint) { | |
+ if (mCompoundButtonHelper != null) { | |
+ mCompoundButtonHelper.setSupportButtonTintList(tint); | |
} | |
- return padding; | |
+ } | |
+ | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Nullable | |
+ @Override | |
+ public ColorStateList getSupportButtonTintList() { | |
+ return mCompoundButtonHelper != null | |
+ ? mCompoundButtonHelper.getSupportButtonTintList() | |
+ : null; | |
+ } | |
+ | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Override | |
+ public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) { | |
+ if (mCompoundButtonHelper != null) { | |
+ mCompoundButtonHelper.setSupportButtonTintMode(tintMode); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat} | |
+ * @hide | |
+ */ | |
+ @Nullable | |
+ @Override | |
+ public PorterDuff.Mode getSupportButtonTintMode() { | |
+ return mCompoundButtonHelper != null | |
+ ? mCompoundButtonHelper.getSupportButtonTintMode() | |
+ : null; | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatRatingBar.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatRatingBar.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatRatingBar.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatRatingBar.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -38,10 +38,10 @@ | |
import android.widget.RatingBar; | |
/** | |
- * A tint aware {@link android.widget.RatingBar}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.RatingBar} in your | |
- * layouts. You should only need to manually use this class when writing custom views. | |
+ * A {@link RatingBar} which supports compatible features on older version of the platform. | |
+ * | |
+ * <p>This will automatically be used when you use {@link RatingBar} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatRatingBar extends RatingBar { | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatSpinner.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatSpinner.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatSpinner.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatSpinner.java 2015-07-15 08:50:04.000000000 +0900 | |
@@ -16,122 +16,459 @@ | |
package android.support.v7.widget; | |
-import android.annotation.TargetApi; | |
import android.content.Context; | |
import android.content.res.ColorStateList; | |
+import android.content.res.Resources; | |
+import android.content.res.TypedArray; | |
+import android.database.DataSetObserver; | |
import android.graphics.PorterDuff; | |
+import android.graphics.Rect; | |
import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
+import android.support.annotation.DrawableRes; | |
import android.support.annotation.Nullable; | |
import android.support.v4.view.TintableBackgroundView; | |
+import android.support.v4.view.ViewCompat; | |
import android.support.v7.appcompat.R; | |
-import android.support.v7.internal.widget.TintInfo; | |
+import android.support.v7.internal.view.ContextThemeWrapper; | |
import android.support.v7.internal.widget.TintManager; | |
import android.support.v7.internal.widget.TintTypedArray; | |
+import android.support.v7.internal.widget.ViewUtils; | |
import android.util.AttributeSet; | |
-import android.widget.ListPopupWindow; | |
+import android.util.Log; | |
+import android.view.MotionEvent; | |
+import android.view.View; | |
+import android.view.ViewGroup; | |
+import android.view.ViewTreeObserver; | |
+import android.widget.AdapterView; | |
+import android.widget.ListAdapter; | |
+import android.widget.ListView; | |
+import android.widget.PopupWindow; | |
import android.widget.Spinner; | |
+import android.widget.SpinnerAdapter; | |
-import java.lang.reflect.Field; | |
/** | |
- * A tint aware {@link android.widget.Spinner}. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.Spinner} in your | |
- * layouts. You should only need to manually use this class when writing custom views. | |
+ * A {@link Spinner} which supports compatible features on older version of the platform, | |
+ * including: | |
+ * <ul> | |
+ * <li>Allows dynamic tint of it background via the background tint methods in | |
+ * {@link android.support.v4.view.ViewCompat}.</li> | |
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and | |
+ * {@link R.attr#backgroundTintMode}.</li> | |
+ * <li>Allows setting of the popups theme using {@link R.attr#popupTheme}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link Spinner} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatSpinner extends Spinner implements TintableBackgroundView { | |
- private static final int[] TINT_ATTRS = { | |
- android.R.attr.background, | |
- android.R.attr.popupBackground | |
- }; | |
+ private static final boolean IS_AT_LEAST_M = Build.VERSION.SDK_INT >= 23; | |
+ private static final boolean IS_AT_LEAST_JB = Build.VERSION.SDK_INT >= 16; | |
+ | |
+ private static final int[] ATTRS_ANDROID_SPINNERMODE = {android.R.attr.spinnerMode}; | |
+ | |
+ private static final int MAX_ITEMS_MEASURED = 15; | |
+ | |
+ private static final String TAG = "AppCompatSpinner"; | |
+ | |
+ private static final int MODE_DIALOG = 0; | |
+ private static final int MODE_DROPDOWN = 1; | |
+ private static final int MODE_THEME = -1; | |
- private TintInfo mInternalBackgroundTint; | |
- private TintInfo mBackgroundTint; | |
private TintManager mTintManager; | |
+ private AppCompatBackgroundHelper mBackgroundTintHelper; | |
+ | |
+ /** Context used to inflate the popup window or dialog. */ | |
+ private Context mPopupContext; | |
+ | |
+ /** Forwarding listener used to implement drag-to-open. */ | |
+ private ListPopupWindow.ForwardingListener mForwardingListener; | |
+ | |
+ /** Temporary holder for setAdapter() calls from the super constructor. */ | |
+ private SpinnerAdapter mTempAdapter; | |
+ | |
+ private boolean mPopupSet; | |
+ | |
+ private DropdownPopup mPopup; | |
+ | |
+ private int mDropDownWidth; | |
+ | |
+ private final Rect mTempRect = new Rect(); | |
+ | |
+ /** | |
+ * Construct a new spinner with the given context's theme. | |
+ * | |
+ * @param context The Context the view is running in, through which it can | |
+ * access the current theme, resources, etc. | |
+ */ | |
public AppCompatSpinner(Context context) { | |
this(context, null); | |
} | |
+ /** | |
+ * Construct a new spinner with the given context's theme and the supplied | |
+ * mode of displaying choices. <code>mode</code> may be one of | |
+ * {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}. | |
+ * | |
+ * @param context The Context the view is running in, through which it can | |
+ * access the current theme, resources, etc. | |
+ * @param mode Constant describing how the user will select choices from the spinner. | |
+ * @see #MODE_DIALOG | |
+ * @see #MODE_DROPDOWN | |
+ */ | |
+ public AppCompatSpinner(Context context, int mode) { | |
+ this(context, null, R.attr.spinnerStyle, mode); | |
+ } | |
+ | |
+ /** | |
+ * Construct a new spinner with the given context's theme and the supplied attribute set. | |
+ * | |
+ * @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. | |
+ */ | |
public AppCompatSpinner(Context context, AttributeSet attrs) { | |
this(context, attrs, R.attr.spinnerStyle); | |
} | |
+ /** | |
+ * Construct a new spinner with the given context's theme, the supplied attribute set, | |
+ * and default style attribute. | |
+ * | |
+ * @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 defStyleAttr An attribute in the current theme that contains a | |
+ * reference to a style resource that supplies default values for | |
+ * the view. Can be 0 to not look for defaults. | |
+ */ | |
public AppCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr) { | |
+ this(context, attrs, defStyleAttr, MODE_THEME); | |
+ } | |
+ | |
+ /** | |
+ * Construct a new spinner with the given context's theme, the supplied attribute set, | |
+ * and default style. <code>mode</code> may be one of {@link #MODE_DIALOG} or | |
+ * {@link #MODE_DROPDOWN} and determines how the user will select choices from the spinner. | |
+ * | |
+ * @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 defStyleAttr An attribute in the current theme that contains a | |
+ * reference to a style resource that supplies default values for | |
+ * the view. Can be 0 to not look for defaults. | |
+ * @param mode Constant describing how the user will select choices from the spinner. | |
+ * @see #MODE_DIALOG | |
+ * @see #MODE_DROPDOWN | |
+ */ | |
+ public AppCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) { | |
+ this(context, attrs, defStyleAttr, mode, null); | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Constructs a new spinner with the given context's theme, the supplied | |
+ * attribute set, default styles, popup mode (one of {@link #MODE_DIALOG} | |
+ * or {@link #MODE_DROPDOWN}), and the context against which the popup | |
+ * should be inflated. | |
+ * | |
+ * @param context The context against which the view is inflated, which | |
+ * provides access to the current theme, resources, etc. | |
+ * @param attrs The attributes of the XML tag that is inflating the view. | |
+ * @param defStyleAttr An attribute in the current theme that contains a | |
+ * reference to a style resource that supplies default | |
+ * values for the view. Can be 0 to not look for | |
+ * defaults. | |
+ * @param mode Constant describing how the user will select choices from | |
+ * the spinner. | |
+ * @param popupTheme The theme against which the dialog or dropdown popup | |
+ * should be inflated. May be {@code null} to use the | |
+ * view theme. If set, this will override any value | |
+ * specified by | |
+ * {@link R.styleable#Spinner_popupTheme}. | |
+ * @see #MODE_DIALOG | |
+ * @see #MODE_DROPDOWN | |
+ */ | |
+ public AppCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode, | |
+ Resources.Theme popupTheme) { | |
super(context, attrs, defStyleAttr); | |
- if (TintManager.SHOULD_BE_USED) { | |
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, | |
- TINT_ATTRS, defStyleAttr, 0); | |
- if (a.hasValue(0)) { | |
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1)); | |
- if (tint != null) { | |
- setInternalBackgroundTint(tint); | |
- } | |
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs, | |
+ R.styleable.Spinner, defStyleAttr, 0); | |
+ | |
+ mTintManager = a.getTintManager(); | |
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager); | |
+ | |
+ if (popupTheme != null) { | |
+ mPopupContext = new ContextThemeWrapper(context, popupTheme); | |
+ } else { | |
+ final int popupThemeResId = a.getResourceId(R.styleable.Spinner_popupTheme, 0); | |
+ if (popupThemeResId != 0) { | |
+ mPopupContext = new ContextThemeWrapper(context, popupThemeResId); | |
+ } else { | |
+ // If we're running on a < M device, we'll use the current context and still handle | |
+ // any dropdown popup | |
+ mPopupContext = !IS_AT_LEAST_M ? context : null; | |
} | |
- if (a.hasValue(1)) { | |
- final Drawable popupBackground = a.getDrawable(1); | |
- if (Build.VERSION.SDK_INT >= 16) { | |
- setPopupBackgroundDrawable(popupBackground); | |
- } else if (Build.VERSION.SDK_INT >= 11) { | |
- setPopupBackgroundDrawableV11(this, popupBackground); | |
+ } | |
+ | |
+ if (mPopupContext != null) { | |
+ if (mode == MODE_THEME) { | |
+ if (Build.VERSION.SDK_INT >= 11) { | |
+ // If we're running on API v11+ we will try and read android:spinnerMode | |
+ TypedArray aa = null; | |
+ try { | |
+ aa = context.obtainStyledAttributes(attrs, ATTRS_ANDROID_SPINNERMODE, | |
+ defStyleAttr, 0); | |
+ if (aa.hasValue(0)) { | |
+ mode = aa.getInt(0, MODE_DIALOG); | |
+ } | |
+ } catch (Exception e) { | |
+ Log.i(TAG, "Could not read android:spinnerMode", e); | |
+ } finally { | |
+ if (aa != null) { | |
+ aa.recycle(); | |
+ } | |
+ } | |
+ } else { | |
+ // Else, we use a default mode of dropdown | |
+ mode = MODE_DROPDOWN; | |
} | |
} | |
- mTintManager = a.getTintManager(); | |
- a.recycle(); | |
+ | |
+ if (mode == MODE_DROPDOWN) { | |
+ final DropdownPopup popup = new DropdownPopup(mPopupContext, attrs, defStyleAttr); | |
+ final TintTypedArray pa = TintTypedArray.obtainStyledAttributes( | |
+ mPopupContext, attrs, R.styleable.Spinner, defStyleAttr, 0); | |
+ mDropDownWidth = pa.getLayoutDimension(R.styleable.Spinner_android_dropDownWidth, | |
+ LayoutParams.WRAP_CONTENT); | |
+ popup.setBackgroundDrawable( | |
+ pa.getDrawable(R.styleable.Spinner_android_popupBackground)); | |
+ popup.setPromptText(a.getString(R.styleable.Spinner_android_prompt)); | |
+ pa.recycle(); | |
+ | |
+ mPopup = popup; | |
+ mForwardingListener = new ListPopupWindow.ForwardingListener(this) { | |
+ @Override | |
+ public ListPopupWindow getPopup() { | |
+ return popup; | |
+ } | |
+ | |
+ @Override | |
+ public boolean onForwardingStarted() { | |
+ if (!mPopup.isShowing()) { | |
+ mPopup.show(); | |
+ } | |
+ return true; | |
+ } | |
+ }; | |
+ } | |
+ } | |
+ a.recycle(); | |
+ | |
+ mPopupSet = true; | |
+ | |
+ // Base constructors can call setAdapter before we initialize mPopup. | |
+ // Finish setting things up if this happened. | |
+ if (mTempAdapter != null) { | |
+ setAdapter(mTempAdapter); | |
+ mTempAdapter = null; | |
+ } | |
+ | |
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); | |
+ } | |
+ | |
+ /** | |
+ * @return the context used to inflate the Spinner's popup or dialog window | |
+ */ | |
+ public Context getPopupContext() { | |
+ if (mPopup != null) { | |
+ return mPopupContext; | |
+ } else if (IS_AT_LEAST_M) { | |
+ return super.getPopupContext(); | |
+ } | |
+ return null; | |
+ } | |
+ | |
+ public void setPopupBackgroundDrawable(Drawable background) { | |
+ if (mPopup != null) { | |
+ mPopup.setBackgroundDrawable(background); | |
+ } else if (IS_AT_LEAST_JB) { | |
+ super.setPopupBackgroundDrawable(background); | |
+ } | |
+ } | |
+ | |
+ public void setPopupBackgroundResource(@DrawableRes int resId) { | |
+ setPopupBackgroundDrawable(getPopupContext().getDrawable(resId)); | |
+ } | |
+ | |
+ public Drawable getPopupBackground() { | |
+ if (mPopup != null) { | |
+ return mPopup.getBackground(); | |
+ } else if (IS_AT_LEAST_JB) { | |
+ return super.getPopupBackground(); | |
} | |
+ return null; | |
+ } | |
+ | |
+ public void setDropDownVerticalOffset(int pixels) { | |
+ if (mPopup != null) { | |
+ mPopup.setVerticalOffset(pixels); | |
+ } else if (IS_AT_LEAST_JB) { | |
+ super.setDropDownVerticalOffset(pixels); | |
+ } | |
+ } | |
+ | |
+ public int getDropDownVerticalOffset() { | |
+ if (mPopup != null) { | |
+ return mPopup.getVerticalOffset(); | |
+ } else if (IS_AT_LEAST_JB) { | |
+ return super.getDropDownVerticalOffset(); | |
+ } | |
+ return 0; | |
+ } | |
+ | |
+ public void setDropDownHorizontalOffset(int pixels) { | |
+ if (mPopup != null) { | |
+ mPopup.setHorizontalOffset(pixels); | |
+ } else if (IS_AT_LEAST_JB) { | |
+ super.setDropDownHorizontalOffset(pixels); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Get the configured horizontal offset in pixels for the spinner's popup window of choices. | |
+ * Only valid in {@link #MODE_DROPDOWN}; other modes will return 0. | |
+ * | |
+ * @return Horizontal offset in pixels | |
+ */ | |
+ public int getDropDownHorizontalOffset() { | |
+ if (mPopup != null) { | |
+ return mPopup.getHorizontalOffset(); | |
+ } else if (IS_AT_LEAST_JB) { | |
+ return super.getDropDownHorizontalOffset(); | |
+ } | |
+ return 0; | |
+ } | |
+ | |
+ public void setDropDownWidth(int pixels) { | |
+ if (mPopup != null) { | |
+ mDropDownWidth = pixels; | |
+ } else if (IS_AT_LEAST_JB) { | |
+ super.setDropDownWidth(pixels); | |
+ } | |
+ } | |
+ | |
+ public int getDropDownWidth() { | |
+ if (mPopup != null) { | |
+ return mDropDownWidth; | |
+ } else if (IS_AT_LEAST_JB) { | |
+ return super.getDropDownWidth(); | |
+ } | |
+ return 0; | |
} | |
@Override | |
- public void setBackgroundResource(int resId) { | |
- super.setBackgroundResource(resId); | |
- // Update the default background tint | |
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null); | |
+ public void setAdapter(SpinnerAdapter adapter) { | |
+ // The super constructor may call setAdapter before we're prepared. | |
+ // Postpone doing anything until we've finished construction. | |
+ if (!mPopupSet) { | |
+ mTempAdapter = adapter; | |
+ return; | |
+ } | |
+ | |
+ super.setAdapter(adapter); | |
+ | |
+ if (mPopup != null) { | |
+ final Context popupContext = mPopupContext == null ? getContext() : mPopupContext; | |
+ mPopup.setAdapter(new DropDownAdapter(adapter, popupContext.getTheme())); | |
+ } | |
} | |
@Override | |
- public void setBackgroundDrawable(Drawable background) { | |
- super.setBackgroundDrawable(background); | |
- // We don't know that this drawable is, so we need to clear the default background tint | |
- setInternalBackgroundTint(null); | |
+ protected void onDetachedFromWindow() { | |
+ super.onDetachedFromWindow(); | |
+ | |
+ if (mPopup != null && mPopup.isShowing()) { | |
+ mPopup.dismiss(); | |
+ } | |
} | |
- @TargetApi(Build.VERSION_CODES.HONEYCOMB) | |
- private static void setPopupBackgroundDrawableV11(Spinner view, Drawable background) { | |
- try { | |
- Field popupField = Spinner.class.getDeclaredField("mPopup"); | |
- popupField.setAccessible(true); | |
+ @Override | |
+ public boolean onTouchEvent(MotionEvent event) { | |
+ if (mForwardingListener != null && mForwardingListener.onTouch(this, event)) { | |
+ return true; | |
+ } | |
+ return super.onTouchEvent(event); | |
+ } | |
- Object popup = popupField.get(view); | |
+ @Override | |
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
- if (popup instanceof ListPopupWindow) { | |
- ((ListPopupWindow) popup).setBackgroundDrawable(background); | |
- } | |
- } catch (NoSuchFieldException e) { | |
- e.printStackTrace(); | |
- } catch (IllegalAccessException e) { | |
- e.printStackTrace(); | |
+ if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { | |
+ final int measuredWidth = getMeasuredWidth(); | |
+ setMeasuredDimension(Math.min(Math.max(measuredWidth, | |
+ compatMeasureContentWidth(getAdapter(), getBackground())), | |
+ MeasureSpec.getSize(widthMeasureSpec)), | |
+ getMeasuredHeight()); | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public boolean performClick() { | |
+ if (mPopup != null && !mPopup.isShowing()) { | |
+ mPopup.show(); | |
+ return true; | |
+ } | |
+ return super.performClick(); | |
+ } | |
+ | |
+ @Override | |
+ public void setPrompt(CharSequence prompt) { | |
+ if (mPopup != null) { | |
+ mPopup.setPromptText(prompt); | |
+ } else { | |
+ super.setPrompt(prompt); | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public CharSequence getPrompt() { | |
+ return mPopup != null ? mPopup.getHintText() : super.getPrompt(); | |
+ } | |
+ | |
+ @Override | |
+ public void setBackgroundResource(@DrawableRes int resId) { | |
+ super.setBackgroundResource(resId); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundResource(resId); | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public void setBackgroundDrawable(Drawable background) { | |
+ super.setBackgroundDrawable(background); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.onSetBackgroundDrawable(background); | |
} | |
} | |
/** | |
* This should be accessed via | |
* {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, | |
- * android.content.res.ColorStateList)} | |
+ * ColorStateList)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint); | |
} | |
- mBackgroundTint.mTintList = tint; | |
- mBackgroundTint.mHasTintList = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -143,24 +480,22 @@ | |
@Override | |
@Nullable | |
public ColorStateList getSupportBackgroundTintList() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; | |
} | |
/** | |
* This should be accessed via | |
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)} | |
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, | |
+ * PorterDuff.Mode)} | |
* | |
* @hide | |
*/ | |
@Override | |
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { | |
- if (mBackgroundTint == null) { | |
- mBackgroundTint = new TintInfo(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); | |
} | |
- mBackgroundTint.mTintMode = tintMode; | |
- mBackgroundTint.mHasTintMode = true; | |
- | |
- applySupportBackgroundTint(); | |
} | |
/** | |
@@ -172,35 +507,311 @@ | |
@Override | |
@Nullable | |
public PorterDuff.Mode getSupportBackgroundTintMode() { | |
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; | |
+ return mBackgroundTintHelper != null | |
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; | |
} | |
@Override | |
protected void drawableStateChanged() { | |
super.drawableStateChanged(); | |
- applySupportBackgroundTint(); | |
+ if (mBackgroundTintHelper != null) { | |
+ mBackgroundTintHelper.applySupportBackgroundTint(); | |
+ } | |
} | |
- private void applySupportBackgroundTint() { | |
- if (getBackground() != null) { | |
- if (mBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mBackgroundTint); | |
- } else if (mInternalBackgroundTint != null) { | |
- TintManager.tintViewBackground(this, mInternalBackgroundTint); | |
+ private int compatMeasureContentWidth(SpinnerAdapter adapter, Drawable background) { | |
+ if (adapter == null) { | |
+ return 0; | |
+ } | |
+ | |
+ int width = 0; | |
+ View itemView = null; | |
+ int itemType = 0; | |
+ final int widthMeasureSpec = | |
+ MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED); | |
+ final int heightMeasureSpec = | |
+ MeasureSpec.makeMeasureSpec(getMeasuredHeight(), 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 LayoutParams( | |
+ LayoutParams.WRAP_CONTENT, | |
+ 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; | |
} | |
- private void setInternalBackgroundTint(ColorStateList tint) { | |
- if (tint != null) { | |
- if (mInternalBackgroundTint == null) { | |
- mInternalBackgroundTint = new TintInfo(); | |
+ /** | |
+ * <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; | |
+ | |
+ /** | |
+ * Creates a new ListAdapter wrapper for the specified adapter. | |
+ * | |
+ * @param adapter the SpinnerAdapter to transform into a ListAdapter | |
+ * @param dropDownTheme the theme against which to inflate drop-down | |
+ * views, may be {@null} to use default theme | |
+ */ | |
+ public DropDownAdapter(@Nullable SpinnerAdapter adapter, | |
+ @Nullable Resources.Theme dropDownTheme) { | |
+ mAdapter = adapter; | |
+ | |
+ if (adapter instanceof ListAdapter) { | |
+ mListAdapter = (ListAdapter) adapter; | |
} | |
- mInternalBackgroundTint.mTintList = tint; | |
- mInternalBackgroundTint.mHasTintList = true; | |
- } else { | |
- mInternalBackgroundTint = null; | |
+ | |
+ if (dropDownTheme != null) { | |
+ if (IS_AT_LEAST_M && adapter instanceof android.widget.ThemedSpinnerAdapter) { | |
+ final android.widget.ThemedSpinnerAdapter themedAdapter = | |
+ (android.widget.ThemedSpinnerAdapter) adapter; | |
+ if (themedAdapter.getDropDownViewTheme() != dropDownTheme) { | |
+ themedAdapter.setDropDownViewTheme(dropDownTheme); | |
+ } | |
+ } else if (adapter instanceof ThemedSpinnerAdapter) { | |
+ final ThemedSpinnerAdapter themedAdapter = (ThemedSpinnerAdapter) adapter; | |
+ if (themedAdapter.getDropDownViewTheme() == null) { | |
+ themedAdapter.setDropDownViewTheme(dropDownTheme); | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ 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; | |
+ } | |
+ } | |
+ | |
+ private class DropdownPopup extends ListPopupWindow { | |
+ private CharSequence mHintText; | |
+ private ListAdapter mAdapter; | |
+ private final Rect mVisibleRect = new Rect(); | |
+ | |
+ public DropdownPopup(Context context, AttributeSet attrs, int defStyleAttr) { | |
+ super(context, attrs, defStyleAttr); | |
+ | |
+ setAnchorView(AppCompatSpinner.this); | |
+ setModal(true); | |
+ setPromptPosition(POSITION_PROMPT_ABOVE); | |
+ | |
+ setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
+ @Override | |
+ public void onItemClick(AdapterView<?> parent, View v, int position, long id) { | |
+ AppCompatSpinner.this.setSelection(position); | |
+ if (getOnItemClickListener() != null) { | |
+ AppCompatSpinner.this | |
+ .performItemClick(v, position, mAdapter.getItemId(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; | |
+ } | |
+ | |
+ void computeContentWidth() { | |
+ final Drawable background = getBackground(); | |
+ int hOffset = 0; | |
+ if (background != null) { | |
+ background.getPadding(mTempRect); | |
+ hOffset = ViewUtils.isLayoutRtl(AppCompatSpinner.this) ? mTempRect.right | |
+ : -mTempRect.left; | |
+ } else { | |
+ mTempRect.left = mTempRect.right = 0; | |
+ } | |
+ | |
+ final int spinnerPaddingLeft = AppCompatSpinner.this.getPaddingLeft(); | |
+ final int spinnerPaddingRight = AppCompatSpinner.this.getPaddingRight(); | |
+ final int spinnerWidth = AppCompatSpinner.this.getWidth(); | |
+ if (mDropDownWidth == WRAP_CONTENT) { | |
+ int contentWidth = compatMeasureContentWidth( | |
+ (SpinnerAdapter) mAdapter, getBackground()); | |
+ final int contentWidthLimit = getContext().getResources() | |
+ .getDisplayMetrics().widthPixels - mTempRect.left - mTempRect.right; | |
+ if (contentWidth > contentWidthLimit) { | |
+ contentWidth = contentWidthLimit; | |
+ } | |
+ setContentWidth(Math.max( | |
+ contentWidth, spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight)); | |
+ } else if (mDropDownWidth == MATCH_PARENT) { | |
+ setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight); | |
+ } else { | |
+ setContentWidth(mDropDownWidth); | |
+ } | |
+ if (ViewUtils.isLayoutRtl(AppCompatSpinner.this)) { | |
+ hOffset += spinnerWidth - spinnerPaddingRight - getWidth(); | |
+ } else { | |
+ hOffset += spinnerPaddingLeft; | |
+ } | |
+ setHorizontalOffset(hOffset); | |
+ } | |
+ | |
+ public void show() { | |
+ final boolean wasShowing = isShowing(); | |
+ | |
+ computeContentWidth(); | |
+ | |
+ setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); | |
+ super.show(); | |
+ final ListView listView = getListView(); | |
+ listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); | |
+ setSelection(AppCompatSpinner.this.getSelectedItemPosition()); | |
+ | |
+ if (wasShowing) { | |
+ // Skip setting up the layout/dismiss listener below. If we were previously | |
+ // showing it will still stick around. | |
+ return; | |
+ } | |
+ | |
+ // Make sure we hide if our anchor goes away. | |
+ // TODO: This might be appropriate to push all the way down to PopupWindow, | |
+ // but it may have other side effects to investigate first. (Text editing handles, etc.) | |
+ final ViewTreeObserver vto = getViewTreeObserver(); | |
+ if (vto != null) { | |
+ final ViewTreeObserver.OnGlobalLayoutListener layoutListener | |
+ = new ViewTreeObserver.OnGlobalLayoutListener() { | |
+ @Override | |
+ public void onGlobalLayout() { | |
+ if (!isVisibleToUser(AppCompatSpinner.this)) { | |
+ dismiss(); | |
+ } else { | |
+ computeContentWidth(); | |
+ | |
+ // Use super.show here to update; we don't want to move the selected | |
+ // position or adjust other things that would be reset otherwise. | |
+ DropdownPopup.super.show(); | |
+ } | |
+ } | |
+ }; | |
+ vto.addOnGlobalLayoutListener(layoutListener); | |
+ setOnDismissListener(new PopupWindow.OnDismissListener() { | |
+ @Override | |
+ public void onDismiss() { | |
+ final ViewTreeObserver vto = getViewTreeObserver(); | |
+ if (vto != null) { | |
+ vto.removeGlobalOnLayoutListener(layoutListener); | |
+ } | |
+ } | |
+ }); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Simplified version of the the hidden View.isVisibleToUser() | |
+ */ | |
+ private boolean isVisibleToUser(View view) { | |
+ return ViewCompat.isAttachedToWindow(view) && view.getGlobalVisibleRect(mVisibleRect); | |
} | |
- applySupportBackgroundTint(); | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatTextHelper.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatTextHelper.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatTextHelper.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatTextHelper.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -0,0 +1,101 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.widget; | |
+ | |
+import android.content.Context; | |
+import android.content.res.ColorStateList; | |
+import android.content.res.TypedArray; | |
+import android.os.Build; | |
+import android.support.v7.appcompat.R; | |
+import android.support.v7.internal.text.AllCapsTransformationMethod; | |
+import android.support.v7.internal.widget.ThemeUtils; | |
+import android.util.AttributeSet; | |
+import android.widget.TextView; | |
+ | |
+class AppCompatTextHelper { | |
+ | |
+ private static final int[] VIEW_ATTRS = {android.R.attr.textAppearance}; | |
+ private static final int[] TEXT_APPEARANCE_ATTRS = {R.attr.textAllCaps}; | |
+ | |
+ private final TextView mView; | |
+ | |
+ AppCompatTextHelper(TextView view) { | |
+ mView = view; | |
+ } | |
+ | |
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { | |
+ Context context = mView.getContext(); | |
+ | |
+ // First read the TextAppearance style id | |
+ TypedArray a = context.obtainStyledAttributes(attrs, VIEW_ATTRS, defStyleAttr, 0); | |
+ final int ap = a.getResourceId(0, -1); | |
+ a.recycle(); | |
+ | |
+ // Now check TextAppearance's textAllCaps value | |
+ if (ap != -1) { | |
+ TypedArray appearance = context.obtainStyledAttributes(ap, R.styleable.TextAppearance); | |
+ if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) { | |
+ setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false)); | |
+ } | |
+ appearance.recycle(); | |
+ } | |
+ | |
+ // Now read the style's value | |
+ a = context.obtainStyledAttributes(attrs, TEXT_APPEARANCE_ATTRS, defStyleAttr, 0); | |
+ if (a.hasValue(0)) { | |
+ setAllCaps(a.getBoolean(0, false)); | |
+ } | |
+ a.recycle(); | |
+ | |
+ final ColorStateList textColors = mView.getTextColors(); | |
+ if (textColors != null && !textColors.isStateful()) { | |
+ // If we have a ColorStateList which isn't stateful, create one which includes | |
+ // a disabled state | |
+ | |
+ final int disabledTextColor; | |
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { | |
+ // Pre-Lollipop, we will use textColorSecondary with android:disabledAlpha | |
+ // applied | |
+ disabledTextColor = ThemeUtils.getDisabledThemeAttrColor(context, | |
+ android.R.attr.textColorSecondary); | |
+ } else { | |
+ // With certain styles on Lollipop, there is a StateListAnimator which sets | |
+ // an alpha on the whole view, so we don't need to apply disabledAlpha to | |
+ // textColorSecondary | |
+ disabledTextColor = ThemeUtils.getThemeAttrColor(context, | |
+ android.R.attr.textColorSecondary); | |
+ } | |
+ | |
+ mView.setTextColor(ThemeUtils.createDisabledStateList( | |
+ textColors.getDefaultColor(), disabledTextColor)); | |
+ } | |
+ } | |
+ | |
+ void onSetTextAppearance(Context context, int resId) { | |
+ TypedArray appearance = context.obtainStyledAttributes(resId, TEXT_APPEARANCE_ATTRS); | |
+ if (appearance.hasValue(0)) { | |
+ setAllCaps(appearance.getBoolean(0, false)); | |
+ } | |
+ appearance.recycle(); | |
+ } | |
+ | |
+ void setAllCaps(boolean allCaps) { | |
+ mView.setTransformationMethod(allCaps | |
+ ? new AllCapsTransformationMethod(mView.getContext()) | |
+ : null); | |
+ } | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/AppCompatTextView.java appcampat-v7-23.0.0/android/support/v7/widget/AppCompatTextView.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/AppCompatTextView.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/AppCompatTextView.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -17,21 +17,25 @@ | |
package android.support.v7.widget; | |
import android.content.Context; | |
-import android.content.res.TypedArray; | |
import android.support.v7.appcompat.R; | |
-import android.support.v7.internal.text.AllCapsTransformationMethod; | |
import android.util.AttributeSet; | |
import android.widget.TextView; | |
/** | |
- * A {@link android.widget.TextView} which supports compatible features on older version of the | |
- * platform. | |
- * <p> | |
- * This will automatically be used when you use {@link android.widget.TextView} in your | |
- * layouts. You should only need to manually use this class when writing custom views. | |
+ * A {@link TextView} which supports compatible features on older version of the platform, | |
+ * including: | |
+ * <ul> | |
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to | |
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li> | |
+ * </ul> | |
+ * | |
+ * <p>This will automatically be used when you use {@link TextView} in your layouts. | |
+ * You should only need to manually use this class when writing custom views.</p> | |
*/ | |
public class AppCompatTextView extends TextView { | |
+ private AppCompatTextHelper mTextHelper; | |
+ | |
public AppCompatTextView(Context context) { | |
this(context, null); | |
} | |
@@ -40,44 +44,18 @@ | |
this(context, attrs, android.R.attr.textViewStyle); | |
} | |
- public AppCompatTextView(Context context, AttributeSet attrs, int defStyle) { | |
- super(context, attrs, defStyle); | |
- | |
- // First read the TextAppearance style id | |
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView, | |
- defStyle, 0); | |
- final int ap = a.getResourceId(R.styleable.AppCompatTextView_android_textAppearance, -1); | |
- a.recycle(); | |
- | |
- // Now check TextAppearance's textAllCaps value | |
- if (ap != -1) { | |
- TypedArray appearance = context.obtainStyledAttributes(ap, R.styleable.TextAppearance); | |
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) { | |
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false)); | |
- } | |
- appearance.recycle(); | |
- } | |
+ public AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) { | |
+ super(context, attrs, defStyleAttr); | |
- // Now read the style's value | |
- a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView, defStyle, 0); | |
- if (a.hasValue(R.styleable.AppCompatTextView_textAllCaps)) { | |
- setAllCaps(a.getBoolean(R.styleable.AppCompatTextView_textAllCaps, false)); | |
- } | |
- a.recycle(); | |
- } | |
- | |
- public void setAllCaps(boolean allCaps) { | |
- setTransformationMethod(allCaps ? new AllCapsTransformationMethod(getContext()) : null); | |
+ mTextHelper = new AppCompatTextHelper(this); | |
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr); | |
} | |
@Override | |
public void setTextAppearance(Context context, int resId) { | |
super.setTextAppearance(context, resId); | |
- | |
- TypedArray appearance = context.obtainStyledAttributes(resId, R.styleable.TextAppearance); | |
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) { | |
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false)); | |
+ if (mTextHelper != null) { | |
+ mTextHelper.onSetTextAppearance(context, resId); | |
} | |
- appearance.recycle(); | |
} | |
} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/PopupMenu.java appcampat-v7-23.0.0/android/support/v7/widget/PopupMenu.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/PopupMenu.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/PopupMenu.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -114,6 +114,29 @@ | |
} | |
/** | |
+ * Sets the gravity used to align the popup window to its anchor view. | |
+ * <p> | |
+ * If the popup is showing, calling this method will take effect only | |
+ * the next time the popup is shown. | |
+ * | |
+ * @param gravity the gravity used to align the popup window | |
+ * | |
+ * @see #getGravity() | |
+ */ | |
+ public void setGravity(int gravity) { | |
+ mPopup.setGravity(gravity); | |
+ } | |
+ | |
+ /** | |
+ * @return the gravity used to align the popup window to its anchor view | |
+ * | |
+ * @see #setGravity(int) | |
+ */ | |
+ public int getGravity() { | |
+ return mPopup.getGravity(); | |
+ } | |
+ | |
+ /** | |
* Returns an {@link android.view.View.OnTouchListener} that can be added to the anchor view | |
* to implement drag-to-open behavior. | |
* <p> | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/ShareActionProvider.java appcampat-v7-23.0.0/android/support/v7/widget/ShareActionProvider.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/ShareActionProvider.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/ShareActionProvider.java 2015-08-12 08:31:34.000000000 +0900 | |
@@ -251,18 +251,19 @@ | |
* 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> | |
+ * | |
+ * <p class="note"> | |
* <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. Therefore, if you want to | |
* use different history files for sharing specific types of content, every time | |
- * you change the history file {@link #setShareHistoryFileName(String)} you must | |
- * call {@link android.app.Activity#invalidateOptionsMenu()} to recreate the | |
- * action view. You should <strong>not</strong> call | |
- * {@link android.app.Activity#invalidateOptionsMenu()} from | |
- * {@link android.app.Activity#onCreateOptionsMenu(Menu)}." | |
- * <p> | |
- * <code> | |
+ * you change the history file with {@link #setShareHistoryFileName(String)} you must | |
+ * call {@link android.support.v7.app.AppCompatActivity#supportInvalidateOptionsMenu()} | |
+ * to recreate the action view. You should <strong>not</strong> call | |
+ * {@link android.support.v7.app.AppCompatActivity#supportInvalidateOptionsMenu()} from | |
+ * {@link android.support.v7.app.AppCompatActivity#onCreateOptionsMenu(Menu)}. | |
+ * | |
+ * <pre> | |
* private void doShare(Intent intent) { | |
* if (IMAGE.equals(intent.getMimeType())) { | |
* mShareActionProvider.setHistoryFileName(SHARE_IMAGE_HISTORY_FILE_NAME); | |
@@ -270,9 +271,9 @@ | |
* mShareActionProvider.setHistoryFileName(SHARE_TEXT_HISTORY_FILE_NAME); | |
* } | |
* mShareActionProvider.setIntent(intent); | |
- * invalidateOptionsMenu(); | |
+ * supportInvalidateOptionsMenu(); | |
* } | |
- * <code> | |
+ * </pre> | |
* | |
* @param shareHistoryFile The share history file name. | |
*/ | |
@@ -284,16 +285,13 @@ | |
/** | |
* 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. | |
* | |
@@ -373,4 +371,4 @@ | |
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); | |
} | |
} | |
-} | |
\ No newline at end of file | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/SwitchCompat.java appcampat-v7-23.0.0/android/support/v7/widget/SwitchCompat.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/SwitchCompat.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/SwitchCompat.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -140,7 +140,7 @@ | |
private Layout mOnLayout; | |
private Layout mOffLayout; | |
private TransformationMethod mSwitchTransformationMethod; | |
- private Animation mPositionAnimator; | |
+ private ThumbAnimation mPositionAnimator; | |
@SuppressWarnings("hiding") | |
private final Rect mTempRect = new Rect(); | |
@@ -748,16 +748,7 @@ | |
} | |
private void animateThumbToCheckedState(boolean newCheckedState) { | |
- final float startPosition = mThumbPosition; | |
- final float targetPosition = newCheckedState ? 1 : 0; | |
- final float diff = targetPosition - startPosition; | |
- | |
- mPositionAnimator = new Animation() { | |
- @Override | |
- protected void applyTransformation(float interpolatedTime, Transformation t) { | |
- setThumbPosition(startPosition + (diff * interpolatedTime)); | |
- } | |
- }; | |
+ mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1 : 0); | |
mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION); | |
startAnimation(mPositionAnimator); | |
} | |
@@ -1111,6 +1102,8 @@ | |
if (mPositionAnimator != null && !mPositionAnimator.hasEnded()) { | |
clearAnimation(); | |
+ // Manually set our thumb position to the end state | |
+ setThumbPosition(mPositionAnimator.mEndPosition); | |
mPositionAnimator = null; | |
} | |
} | |
@@ -1148,4 +1141,21 @@ | |
private static float constrain(float amount, float low, float high) { | |
return amount < low ? low : (amount > high ? high : amount); | |
} | |
+ | |
+ private class ThumbAnimation extends Animation { | |
+ final float mStartPosition; | |
+ final float mEndPosition; | |
+ final float mDiff; | |
+ | |
+ private ThumbAnimation(float startPosition, float endPosition) { | |
+ mStartPosition = startPosition; | |
+ mEndPosition = endPosition; | |
+ mDiff = endPosition - startPosition; | |
+ } | |
+ | |
+ @Override | |
+ protected void applyTransformation(float interpolatedTime, Transformation t) { | |
+ setThumbPosition(mStartPosition + (mDiff * interpolatedTime)); | |
+ } | |
+ } | |
} | |
\ No newline at end of file | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/ThemedSpinnerAdapter.java appcampat-v7-23.0.0/android/support/v7/widget/ThemedSpinnerAdapter.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/ThemedSpinnerAdapter.java 1970-01-01 09:00:00.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/ThemedSpinnerAdapter.java 2015-07-31 23:24:46.000000000 +0900 | |
@@ -0,0 +1,154 @@ | |
+/* | |
+ * Copyright (C) 2015 The Android Open Source Project | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package android.support.v7.widget; | |
+ | |
+ | |
+import android.content.Context; | |
+import android.content.res.Resources; | |
+import android.content.res.Resources.Theme; | |
+import android.support.annotation.NonNull; | |
+import android.support.annotation.Nullable; | |
+import android.support.v7.internal.view.ContextThemeWrapper; | |
+import android.view.LayoutInflater; | |
+import android.view.View; | |
+import android.view.ViewGroup; | |
+import android.widget.SpinnerAdapter; | |
+ | |
+/** | |
+ * An extension of SpinnerAdapter that is capable of inflating drop-down views | |
+ * against a different theme than normal views. | |
+ * <p> | |
+ * Classes that implement this interface should use the theme provided to | |
+ * {@link #setDropDownViewTheme(Theme)} when creating views in | |
+ * {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}. | |
+ * | |
+ * <p>The {@link Helper} class is provided to aide implementation in a backwards compatible way. | |
+ * </p> | |
+ */ | |
+public interface ThemedSpinnerAdapter extends SpinnerAdapter { | |
+ /** | |
+ * Sets the {@link Resources.Theme} against which drop-down views are | |
+ * inflated. | |
+ * | |
+ * @param theme the context against which to inflate drop-down views, or | |
+ * {@code null} to use the default theme | |
+ * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup) | |
+ */ | |
+ void setDropDownViewTheme(@Nullable Resources.Theme theme); | |
+ | |
+ /** | |
+ * Returns the value previously set by a call to | |
+ * {@link #setDropDownViewTheme(Theme)}. | |
+ * | |
+ * @return the {@link Resources.Theme} against which drop-down views are | |
+ * inflated, or {@code null} if one has not been explicitly set | |
+ */ | |
+ @Nullable | |
+ Resources.Theme getDropDownViewTheme(); | |
+ | |
+ /** | |
+ * A helper class which allows easy integration of {@link ThemedSpinnerAdapter} into existing | |
+ * {@link SpinnerAdapter}s in a backwards compatible way. | |
+ * | |
+ * <p>An example {@link android.widget.BaseAdapter BaseAdapter} implementation would be:</p> | |
+ * | |
+ * <pre> | |
+ * public class MyAdapter extends BaseAdapter implements ThemedSpinnerAdapter { | |
+ * private final ThemedSpinnerAdapter.Helper mDropDownHelper; | |
+ * | |
+ * public CheeseAdapter(Context context) { | |
+ * mDropDownHelper = new ThemedSpinnerAdapter.Helper(context); | |
+ * // ... | |
+ * } | |
+ * | |
+ * @Override | |
+ * public View getDropDownView(int position, View convertView, ViewGroup parent) { | |
+ * View view; | |
+ * | |
+ * if (convertView == null) { | |
+ * // Inflate the drop down using the helper's LayoutInflater | |
+ * LayoutInflater inflater = mDropDownHelper.getDropDownViewInflater(); | |
+ * view = inflater.inflate(R.layout.my_dropdown, parent, false); | |
+ * } | |
+ * | |
+ * // ... | |
+ * } | |
+ * | |
+ * @Override | |
+ * public void setDropDownViewTheme(@Nullable Resources.Theme theme) { | |
+ * // Pass the new theme to the helper | |
+ * mDropDownHelper.setDropDownViewTheme(theme); | |
+ * } | |
+ * | |
+ * @Override | |
+ * public Resources.Theme getDropDownViewTheme() { | |
+ * // Return the helper's value | |
+ * return mDropDownHelper.getDropDownViewTheme(); | |
+ * } | |
+ * } | |
+ * </pre> | |
+ */ | |
+ public final static class Helper { | |
+ private final Context mContext; | |
+ private final LayoutInflater mInflater; | |
+ private LayoutInflater mDropDownInflater; | |
+ | |
+ public Helper(@NonNull Context context) { | |
+ mContext = context; | |
+ mInflater = LayoutInflater.from(context); | |
+ } | |
+ | |
+ /** | |
+ * Should be called from your adapter's | |
+ * {@link ThemedSpinnerAdapter#setDropDownViewTheme(Theme)} | |
+ * | |
+ * @param theme the theme passed in to | |
+ * {@link ThemedSpinnerAdapter#setDropDownViewTheme(Theme)} | |
+ */ | |
+ public void setDropDownViewTheme(@Nullable Resources.Theme theme) { | |
+ if (theme == null) { | |
+ mDropDownInflater = null; | |
+ } else if (theme == mContext.getTheme()) { | |
+ mDropDownInflater = mInflater; | |
+ } else { | |
+ final Context context = new ContextThemeWrapper(mContext, theme); | |
+ mDropDownInflater = LayoutInflater.from(context); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Should be called from your adapter's {@link ThemedSpinnerAdapter#getDropDownViewTheme()}, | |
+ * returning the value returned from this method. | |
+ */ | |
+ @Nullable | |
+ public Resources.Theme getDropDownViewTheme() { | |
+ return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme(); | |
+ } | |
+ | |
+ /** | |
+ * Returns the {@link LayoutInflater} which should be used when inflating any layouts | |
+ * from your {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}. | |
+ * | |
+ * <p>The instance returned will have a correct theme, meaning that any inflated views | |
+ * will be created with the same theme.</p> | |
+ */ | |
+ @NonNull | |
+ public LayoutInflater getDropDownViewInflater() { | |
+ return mDropDownInflater != null ? mDropDownInflater : mInflater; | |
+ } | |
+ } | |
+} | |
diff -Nur appcampat-v7-22.2.1/android/support/v7/widget/Toolbar.java appcampat-v7-23.0.0/android/support/v7/widget/Toolbar.java | |
--- appcampat-v7-22.2.1/android/support/v7/widget/Toolbar.java 2015-07-17 03:08:30.000000000 +0900 | |
+++ appcampat-v7-23.0.0/android/support/v7/widget/Toolbar.java 2015-06-23 08:43:44.000000000 +0900 | |
@@ -17,12 +17,20 @@ | |
package android.support.v7.widget; | |
import android.content.Context; | |
+import android.content.res.ColorStateList; | |
import android.content.res.TypedArray; | |
+import android.graphics.PorterDuff; | |
import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
import android.os.Parcel; | |
import android.os.Parcelable; | |
+import android.support.annotation.ColorInt; | |
+import android.support.annotation.DrawableRes; | |
+import android.support.annotation.MenuRes; | |
+import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
+import android.support.annotation.StringRes; | |
+import android.support.annotation.StyleRes; | |
import android.support.v4.view.GravityCompat; | |
import android.support.v4.view.MarginLayoutParamsCompat; | |
import android.support.v4.view.MenuItemCompat; | |
@@ -30,6 +38,7 @@ | |
import android.support.v4.view.ViewCompat; | |
import android.support.v7.app.ActionBar; | |
import android.support.v7.appcompat.R; | |
+import android.support.v7.graphics.drawable.DrawableUtils; | |
import android.support.v7.internal.view.SupportMenuInflater; | |
import android.support.v7.internal.view.menu.MenuBuilder; | |
import android.support.v7.internal.view.menu.MenuItemImpl; | |
@@ -38,6 +47,7 @@ | |
import android.support.v7.internal.view.menu.SubMenuBuilder; | |
import android.support.v7.internal.widget.DecorToolbar; | |
import android.support.v7.internal.widget.RtlSpacingHelper; | |
+import android.support.v7.internal.widget.TintInfo; | |
import android.support.v7.internal.widget.TintManager; | |
import android.support.v7.internal.widget.TintTypedArray; | |
import android.support.v7.internal.widget.ToolbarWidgetWrapper; | |
@@ -79,7 +89,9 @@ | |
* <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close, | |
* collapse, done or another glyph of the app's choosing. This button should always be used | |
* to access other navigational destinations within the container of the Toolbar and | |
- * its signified content or otherwise leave the current context signified by the Toolbar.</li> | |
+ * its signified content or otherwise leave the current context signified by the Toolbar. | |
+ * The navigation button is vertically aligned within the Toolbar's minimum height, | |
+ * if set.</li> | |
* <li><em>A branded logo image.</em> This may extend to the height of the bar and can be | |
* arbitrarily wide.</li> | |
* <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current | |
@@ -95,8 +107,9 @@ | |
* <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the | |
* end of the Toolbar offering a few | |
* <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons"> | |
- * frequent, important or typical</a> actions along with an optional overflow menu for | |
- * additional actions.</li> | |
+ * frequent, important or typical</a> actions along with an optional overflow menu for | |
+ * additional actions. Action buttons are vertically aligned within the Toolbar's | |
+ * minimum height, if set.</li> | |
* </ul> | |
* </p> | |
* | |
@@ -152,6 +165,9 @@ | |
// Clear me after use. | |
private final ArrayList<View> mTempViews = new ArrayList<View>(); | |
+ // Used to hold views that will be removed while we have an expanded action view. | |
+ private final ArrayList<View> mHiddenViews = new ArrayList<>(); | |
+ | |
private final int[] mTempMargins = new int[2]; | |
private OnMenuItemClickListener mOnMenuItemClickListener; | |
@@ -271,6 +287,23 @@ | |
setNavigationContentDescription(navDesc); | |
} | |
+ final Drawable logo = a.getDrawable(R.styleable.Toolbar_logo); | |
+ if (logo != null) { | |
+ setLogo(logo); | |
+ } | |
+ | |
+ final CharSequence logoDesc = a.getText(R.styleable.Toolbar_logoDescription); | |
+ if (!TextUtils.isEmpty(logoDesc)) { | |
+ setLogoDescription(logoDesc); | |
+ } | |
+ | |
+ if (a.hasValue(R.styleable.Toolbar_titleTextColor)) { | |
+ setTitleTextColor(a.getColor(R.styleable.Toolbar_titleTextColor, 0xffffffff)); | |
+ } | |
+ | |
+ if (a.hasValue(R.styleable.Toolbar_subtitleTextColor)) { | |
+ setSubtitleTextColor(a.getColor(R.styleable.Toolbar_subtitleTextColor, 0xffffffff)); | |
+ } | |
a.recycle(); | |
// Keep the TintManager in case we need it later | |
@@ -284,7 +317,7 @@ | |
* @param resId theme used to inflate popup menus | |
* @see #getPopupTheme() | |
*/ | |
- public void setPopupTheme(int resId) { | |
+ public void setPopupTheme(@StyleRes int resId) { | |
if (mPopupTheme != resId) { | |
mPopupTheme = resId; | |
if (resId == 0) { | |
@@ -320,7 +353,7 @@ | |
* | |
* @param resId ID of a drawable resource | |
*/ | |
- public void setLogo(int resId) { | |
+ public void setLogo(@DrawableRes int resId) { | |
setLogo(mTintManager.getDrawable(resId)); | |
} | |
@@ -439,12 +472,12 @@ | |
public void setLogo(Drawable drawable) { | |
if (drawable != null) { | |
ensureLogoView(); | |
- if (mLogoView.getParent() == null) { | |
- addSystemView(mLogoView); | |
- updateChildVisibilityForExpandedActionView(mLogoView); | |
+ if (!isChildOrHidden(mLogoView)) { | |
+ addSystemView(mLogoView, true); | |
} | |
- } else if (mLogoView != null && mLogoView.getParent() != null) { | |
+ } else if (mLogoView != null && isChildOrHidden(mLogoView)) { | |
removeView(mLogoView); | |
+ mHiddenViews.remove(mLogoView); | |
} | |
if (mLogoView != null) { | |
mLogoView.setImageDrawable(drawable); | |
@@ -470,7 +503,7 @@ | |
* | |
* @param resId String resource id | |
*/ | |
- public void setLogoDescription(int resId) { | |
+ public void setLogoDescription(@StringRes int resId) { | |
setLogoDescription(getContext().getText(resId)); | |
} | |
@@ -555,7 +588,7 @@ | |
* | |
* @param resId Resource ID of a string to set as the title | |
*/ | |
- public void setTitle(int resId) { | |
+ public void setTitle(@StringRes int resId) { | |
setTitle(getContext().getText(resId)); | |
} | |
@@ -581,12 +614,12 @@ | |
mTitleTextView.setTextColor(mTitleTextColor); | |
} | |
} | |
- if (mTitleTextView.getParent() == null) { | |
- addSystemView(mTitleTextView); | |
- updateChildVisibilityForExpandedActionView(mTitleTextView); | |
+ if (!isChildOrHidden(mTitleTextView)) { | |
+ addSystemView(mTitleTextView, true); | |
} | |
- } else if (mTitleTextView != null && mTitleTextView.getParent() != null) { | |
+ } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) { | |
removeView(mTitleTextView); | |
+ mHiddenViews.remove(mTitleTextView); | |
} | |
if (mTitleTextView != null) { | |
mTitleTextView.setText(title); | |
@@ -610,7 +643,7 @@ | |
* | |
* @param resId String resource ID | |
*/ | |
- public void setSubtitle(int resId) { | |
+ public void setSubtitle(@StringRes int resId) { | |
setSubtitle(getContext().getText(resId)); | |
} | |
@@ -635,12 +668,12 @@ | |
mSubtitleTextView.setTextColor(mSubtitleTextColor); | |
} | |
} | |
- if (mSubtitleTextView.getParent() == null) { | |
- addSystemView(mSubtitleTextView); | |
- updateChildVisibilityForExpandedActionView(mSubtitleTextView); | |
+ if (!isChildOrHidden(mSubtitleTextView)) { | |
+ addSystemView(mSubtitleTextView, true); | |
} | |
- } else if (mSubtitleTextView != null && mSubtitleTextView.getParent() != null) { | |
+ } else if (mSubtitleTextView != null && isChildOrHidden(mSubtitleTextView)) { | |
removeView(mSubtitleTextView); | |
+ mHiddenViews.remove(mSubtitleTextView); | |
} | |
if (mSubtitleTextView != null) { | |
mSubtitleTextView.setText(subtitle); | |
@@ -652,7 +685,7 @@ | |
* Sets the text color, size, style, hint color, and highlight color | |
* from the specified TextAppearance resource. | |
*/ | |
- public void setTitleTextAppearance(Context context, int resId) { | |
+ public void setTitleTextAppearance(Context context, @StyleRes int resId) { | |
mTitleTextAppearance = resId; | |
if (mTitleTextView != null) { | |
mTitleTextView.setTextAppearance(context, resId); | |
@@ -663,7 +696,7 @@ | |
* Sets the text color, size, style, hint color, and highlight color | |
* from the specified TextAppearance resource. | |
*/ | |
- public void setSubtitleTextAppearance(Context context, int resId) { | |
+ public void setSubtitleTextAppearance(Context context, @StyleRes int resId) { | |
mSubtitleTextAppearance = resId; | |
if (mSubtitleTextView != null) { | |
mSubtitleTextView.setTextAppearance(context, resId); | |
@@ -675,7 +708,7 @@ | |
* | |
* @param color The new text color in 0xAARRGGBB format | |
*/ | |
- public void setTitleTextColor(int color) { | |
+ public void setTitleTextColor(@ColorInt int color) { | |
mTitleTextColor = color; | |
if (mTitleTextView != null) { | |
mTitleTextView.setTextColor(color); | |
@@ -687,7 +720,7 @@ | |
* | |
* @param color The new text color in 0xAARRGGBB format | |
*/ | |
- public void setSubtitleTextColor(int color) { | |
+ public void setSubtitleTextColor(@ColorInt int color) { | |
mSubtitleTextColor = color; | |
if (mSubtitleTextView != null) { | |
mSubtitleTextView.setTextColor(color); | |
@@ -714,7 +747,7 @@ | |
* @param resId Resource ID of a content description string to set, or 0 to | |
* clear the description | |
*/ | |
- public void setNavigationContentDescription(int resId) { | |
+ public void setNavigationContentDescription(@StringRes int resId) { | |
setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null); | |
} | |
@@ -734,7 +767,7 @@ | |
mNavButtonView.setContentDescription(description); | |
} | |
} | |
- | |
+ | |
/** | |
* Set the icon to use for the toolbar's navigation button. | |
* | |
@@ -747,7 +780,7 @@ | |
* | |
* @param resId Resource ID of a drawable to set | |
*/ | |
- public void setNavigationIcon(int resId) { | |
+ public void setNavigationIcon(@DrawableRes int resId) { | |
setNavigationIcon(mTintManager.getDrawable(resId)); | |
} | |
@@ -766,12 +799,12 @@ | |
public void setNavigationIcon(@Nullable Drawable icon) { | |
if (icon != null) { | |
ensureNavButtonView(); | |
- if (mNavButtonView.getParent() == null) { | |
- addSystemView(mNavButtonView); | |
- updateChildVisibilityForExpandedActionView(mNavButtonView); | |
+ if (!isChildOrHidden(mNavButtonView)) { | |
+ addSystemView(mNavButtonView, true); | |
} | |
- } else if (mNavButtonView != null && mNavButtonView.getParent() != null) { | |
+ } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) { | |
removeView(mNavButtonView); | |
+ mHiddenViews.remove(mNavButtonView); | |
} | |
if (mNavButtonView != null) { | |
mNavButtonView.setImageDrawable(icon); | |
@@ -815,6 +848,27 @@ | |
return mMenuView.getMenu(); | |
} | |
+ /** | |
+ * Set the icon to use for the overflow button. | |
+ * | |
+ * @param icon Drawable to set, may be null to clear the icon | |
+ */ | |
+ public void setOverflowIcon(@Nullable Drawable icon) { | |
+ ensureMenu(); | |
+ mMenuView.setOverflowIcon(icon); | |
+ } | |
+ | |
+ /** | |
+ * Return the current drawable used as the overflow icon. | |
+ * | |
+ * @return The overflow icon drawable | |
+ */ | |
+ @Nullable | |
+ public Drawable getOverflowIcon() { | |
+ ensureMenu(); | |
+ return mMenuView.getOverflowIcon(); | |
+ } | |
+ | |
private void ensureMenu() { | |
ensureMenuView(); | |
if (mMenuView.peekMenu() == null) { | |
@@ -837,7 +891,7 @@ | |
final LayoutParams lp = generateDefaultLayoutParams(); | |
lp.gravity = GravityCompat.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK); | |
mMenuView.setLayoutParams(lp); | |
- addSystemView(mMenuView); | |
+ addSystemView(mMenuView, false); | |
} | |
} | |
@@ -853,7 +907,7 @@ | |
* | |
* @param resId ID of a menu resource to inflate | |
*/ | |
- public void inflateMenu(int resId) { | |
+ public void inflateMenu(@MenuRes int resId) { | |
getMenuInflater().inflate(resId, getMenu()); | |
} | |
@@ -1014,7 +1068,7 @@ | |
} | |
} | |
- private void addSystemView(View v) { | |
+ private void addSystemView(View v, boolean allowHide) { | |
final ViewGroup.LayoutParams vlp = v.getLayoutParams(); | |
final LayoutParams lp; | |
if (vlp == null) { | |
@@ -1025,7 +1079,13 @@ | |
lp = (LayoutParams) vlp; | |
} | |
lp.mViewType = LayoutParams.SYSTEM; | |
- addView(v, lp); | |
+ | |
+ if (allowHide && mExpandedActionView != null) { | |
+ v.setLayoutParams(lp); | |
+ mHiddenViews.add(v); | |
+ } else { | |
+ addView(v, lp); | |
+ } | |
} | |
@Override | |
@@ -1729,22 +1789,30 @@ | |
return mWrapper; | |
} | |
- private void setChildVisibilityForExpandedActionView(boolean expand) { | |
+ void removeChildrenForExpandedActionView() { | |
final int childCount = getChildCount(); | |
- for (int i = 0; i < childCount; i++) { | |
+ // Go backwards since we're removing from the list | |
+ for (int i = childCount - 1; i >= 0; i--) { | |
final View child = getChildAt(i); | |
final LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) { | |
- child.setVisibility(expand ? GONE : VISIBLE); | |
+ removeViewAt(i); | |
+ mHiddenViews.add(child); | |
} | |
} | |
} | |
- private void updateChildVisibilityForExpandedActionView(View child) { | |
- final LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
- if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) { | |
- child.setVisibility(mExpandedActionView != null ? GONE : VISIBLE); | |
+ void addChildrenForExpandedActionView() { | |
+ final int count = mHiddenViews.size(); | |
+ // Re-add in reverse order since we removed in reverse order | |
+ for (int i = count - 1; i >= 0; i--) { | |
+ addView(mHiddenViews.get(i)); | |
} | |
+ mHiddenViews.clear(); | |
+ } | |
+ | |
+ private boolean isChildOrHidden(View child) { | |
+ return child.getParent() == this || mHiddenViews.contains(child); | |
} | |
/** | |
@@ -1797,7 +1865,7 @@ | |
int mViewType = CUSTOM; | |
- public LayoutParams(Context c, AttributeSet attrs) { | |
+ public LayoutParams(@NonNull Context c, AttributeSet attrs) { | |
super(c, attrs); | |
} | |
@@ -1954,7 +2022,7 @@ | |
addView(mExpandedActionView); | |
} | |
- setChildVisibilityForExpandedActionView(true); | |
+ removeChildrenForExpandedActionView(); | |
requestLayout(); | |
item.setActionViewExpanded(true); | |
@@ -1977,7 +2045,7 @@ | |
removeView(mCollapseButtonView); | |
mExpandedActionView = null; | |
- setChildVisibilityForExpandedActionView(false); | |
+ addChildrenForExpandedActionView(); | |
mCurrentExpandedItem = null; | |
requestLayout(); | |
item.setActionViewExpanded(false); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment