Skip to content

Instantly share code, notes, and snippets.

@zaki50
Created August 18, 2015 07:51
Show Gist options
  • Save zaki50/231a91dfb71ff751fba6 to your computer and use it in GitHub Desktop.
Save zaki50/231a91dfb71ff751fba6 to your computer and use it in GitHub Desktop.
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);
+ * // ...
+ * }
+ *
+ * &#064;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);
+ * }
+ *
+ * // ...
+ * }
+ *
+ * &#064;Override
+ * public void setDropDownViewTheme(@Nullable Resources.Theme theme) {
+ * // Pass the new theme to the helper
+ * mDropDownHelper.setDropDownViewTheme(theme);
+ * }
+ *
+ * &#064;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