Merge "Another ViewCompat cleanup after minSdk 14 bump."
diff --git a/api/current.txt b/api/current.txt
index 1cb1ecf..63c69c9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6546,6 +6546,8 @@
public final class MediaControllerCompat {
ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
+ method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat);
+ method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
method public void adjustVolume(int, int);
method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
method public android.os.Bundle getExtras();
@@ -6566,6 +6568,8 @@
method public boolean isShuffleModeEnabled();
method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
+ method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat);
+ method public void removeQueueItemAt(int);
method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat);
method public void setVolumeTo(int, int);
@@ -6652,11 +6656,14 @@
method public void setSessionActivity(android.app.PendingIntent);
method public void setShuffleModeEnabled(boolean);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
public static abstract class MediaSessionCompat.Callback {
ctor public MediaSessionCompat.Callback();
+ method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat);
+ method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void onCustomAction(java.lang.String, android.os.Bundle);
method public void onFastForward();
@@ -6670,6 +6677,8 @@
method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
+ method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat);
+ method public void onRemoveQueueItemAt(int);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.support.v4.media.RatingCompat);
@@ -7782,9 +7791,9 @@
method public static int getLayoutMode(android.view.ViewGroup);
method public static int getNestedScrollAxes(android.view.ViewGroup);
method public static boolean isTransitionGroup(android.view.ViewGroup);
- method public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public static deprecated boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
method public static void setLayoutMode(android.view.ViewGroup, int);
- method public static void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
+ method public static deprecated void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
method public static void setTransitionGroup(android.view.ViewGroup, boolean);
field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
@@ -7873,7 +7882,7 @@
method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
- method public static boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public static deprecated boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
}
public final class ViewPropertyAnimatorCompat {
@@ -8518,15 +8527,16 @@
}
public final class EdgeEffectCompat {
- ctor public EdgeEffectCompat(android.content.Context);
- method public boolean draw(android.graphics.Canvas);
- method public void finish();
- method public boolean isFinished();
- method public boolean onAbsorb(int);
+ ctor public deprecated EdgeEffectCompat(android.content.Context);
+ method public deprecated boolean draw(android.graphics.Canvas);
+ method public deprecated void finish();
+ method public deprecated boolean isFinished();
+ method public deprecated boolean onAbsorb(int);
method public deprecated boolean onPull(float);
- method public boolean onPull(float, float);
- method public boolean onRelease();
- method public void setSize(int, int);
+ method public deprecated boolean onPull(float, float);
+ method public static void onPull(android.widget.EdgeEffect, float, float);
+ method public deprecated boolean onRelease();
+ method public deprecated void setSize(int, int);
}
public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
diff --git a/compat/api21/android/support/v4/view/ViewGroupCompatLollipop.java b/compat/api21/android/support/v4/view/ViewGroupCompatLollipop.java
deleted file mode 100644
index 4a14377..0000000
--- a/compat/api21/android/support/v4/view/ViewGroupCompatLollipop.java
+++ /dev/null
@@ -1,36 +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.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(21)
-class ViewGroupCompatLollipop {
-
- public static void setTransitionGroup(ViewGroup group, boolean isTransitionGroup) {
- group.setTransitionGroup(isTransitionGroup);
- }
-
- public static boolean isTransitionGroup(ViewGroup group) {
- return group.isTransitionGroup();
- }
-
- public static int getNestedScrollAxes(ViewGroup group) {
- return group.getNestedScrollAxes();
- }
-}
diff --git a/compat/api21/android/support/v4/view/ViewParentCompatLollipop.java b/compat/api21/android/support/v4/view/ViewParentCompatLollipop.java
deleted file mode 100644
index f64db1e..0000000
--- a/compat/api21/android/support/v4/view/ViewParentCompatLollipop.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewParent;
-
-@RequiresApi(21)
-class ViewParentCompatLollipop {
- private static final String TAG = "ViewParentCompat";
-
- public static boolean onStartNestedScroll(ViewParent parent, View child, View target,
- int nestedScrollAxes) {
- try {
- return parent.onStartNestedScroll(child, target, nestedScrollAxes);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
- "method onStartNestedScroll", e);
- return false;
- }
- }
-
- public static void onNestedScrollAccepted(ViewParent parent, View child, View target,
- int nestedScrollAxes) {
- try {
- parent.onNestedScrollAccepted(child, target, nestedScrollAxes);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
- "method onNestedScrollAccepted", e);
- }
- }
-
- public static void onStopNestedScroll(ViewParent parent, View target) {
- try {
- parent.onStopNestedScroll(target);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
- "method onStopNestedScroll", e);
- }
- }
-
- public static void onNestedScroll(ViewParent parent, View target, int dxConsumed,
- int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
- try {
- parent.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
- "method onNestedScroll", e);
- }
- }
-
- public static void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
- int[] consumed) {
- try {
- parent.onNestedPreScroll(target, dx, dy, consumed);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
- "method onNestedPreScroll", e);
- }
- }
-
- public static boolean onNestedFling(ViewParent parent, View target, float velocityX,
- float velocityY, boolean consumed) {
- try {
- return parent.onNestedFling(target, velocityX, velocityY, consumed);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
- "method onNestedFling", e);
- return false;
- }
- }
-
- public static boolean onNestedPreFling(ViewParent parent, View target, float velocityX,
- float velocityY) {
- try {
- return parent.onNestedPreFling(target, velocityX, velocityY);
- } catch (AbstractMethodError e) {
- Log.e(TAG, "ViewParent " + parent + " does not implement interface " +
- "method onNestedPreFling", e);
- return false;
- }
- }
-}
diff --git a/compat/api21/android/support/v4/widget/EdgeEffectCompatLollipop.java b/compat/api21/android/support/v4/widget/EdgeEffectCompatLollipop.java
deleted file mode 100644
index 017a6b0..0000000
--- a/compat/api21/android/support/v4/widget/EdgeEffectCompatLollipop.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.v4.widget;
-
-import android.support.annotation.RequiresApi;
-import android.widget.EdgeEffect;
-
-@RequiresApi(21)
-class EdgeEffectCompatLollipop {
- public static boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
- ((EdgeEffect) edgeEffect).onPull(deltaDistance, displacement);
- return true;
- }
-}
diff --git a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java b/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
deleted file mode 100644
index c51f175..0000000
--- a/compat/api23/android/support/v4/graphics/PaintCompatApi23.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 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.v4.graphics;
-
-import android.graphics.Paint;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-
-@RequiresApi(23)
-class PaintCompatApi23 {
- static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
- return paint.hasGlyph(string);
- }
-}
diff --git a/compat/honeycomb/android/support/v4/view/ViewGroupCompatHC.java b/compat/honeycomb/android/support/v4/view/ViewGroupCompatHC.java
deleted file mode 100644
index 4e010c6..0000000
--- a/compat/honeycomb/android/support/v4/view/ViewGroupCompatHC.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2013 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.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(11)
-class ViewGroupCompatHC {
- private ViewGroupCompatHC() {
- }
-
- public static void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
- group.setMotionEventSplittingEnabled(split);
- }
-}
diff --git a/compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java b/compat/ics/android/support/v4/graphics/PaintCompatApi14.java
similarity index 97%
rename from compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java
rename to compat/ics/android/support/v4/graphics/PaintCompatApi14.java
index 0d1076f..b459623 100644
--- a/compat/gingerbread/android/support/v4/graphics/PaintCompatGingerbread.java
+++ b/compat/ics/android/support/v4/graphics/PaintCompatApi14.java
@@ -19,11 +19,9 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
import android.support.v4.util.Pair;
-@RequiresApi(9)
-class PaintCompatGingerbread {
+class PaintCompatApi14 {
// U+DFFFD which is very end of unassigned plane.
private static final String TOFU_STRING = "\uDB3F\uDFFD";
diff --git a/compat/ics/android/support/v4/view/ViewGroupCompatIcs.java b/compat/ics/android/support/v4/view/ViewGroupCompatIcs.java
deleted file mode 100644
index d2a0237..0000000
--- a/compat/ics/android/support/v4/view/ViewGroupCompatIcs.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-
-/**
- * ICS specific ViewGroup API implementation.
- */
-
-@RequiresApi(14)
-class ViewGroupCompatIcs {
- public static boolean onRequestSendAccessibilityEvent(ViewGroup group, View child,
- AccessibilityEvent event) {
- return group.onRequestSendAccessibilityEvent(child, event);
- }
-}
diff --git a/compat/ics/android/support/v4/view/ViewParentCompatICS.java b/compat/ics/android/support/v4/view/ViewParentCompatICS.java
deleted file mode 100644
index 69fefb5..0000000
--- a/compat/ics/android/support/v4/view/ViewParentCompatICS.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2013 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.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-
-/**
- * ICS-specific ViewParent API implementation.
- */
-
-@RequiresApi(14)
-class ViewParentCompatICS {
- public static boolean requestSendAccessibilityEvent(
- ViewParent parent, View child, AccessibilityEvent event) {
- return parent.requestSendAccessibilityEvent(child, event);
- }
-}
diff --git a/compat/ics/android/support/v4/widget/EdgeEffectCompatIcs.java b/compat/ics/android/support/v4/widget/EdgeEffectCompatIcs.java
deleted file mode 100644
index 05e3e80..0000000
--- a/compat/ics/android/support/v4/widget/EdgeEffectCompatIcs.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v4.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.support.annotation.RequiresApi;
-import android.widget.EdgeEffect;
-
-/**
- * Stub implementation that contains a real EdgeEffect on ICS.
- * <p/>
- * This class is an implementation detail for EdgeEffectCompat
- * and should not be used directly.
- */
-
-@RequiresApi(14)
-class EdgeEffectCompatIcs {
- public static Object newEdgeEffect(Context context) {
- return new EdgeEffect(context);
- }
-
- public static void setSize(Object edgeEffect, int width, int height) {
- ((EdgeEffect) edgeEffect).setSize(width, height);
- }
-
- public static boolean isFinished(Object edgeEffect) {
- return ((EdgeEffect) edgeEffect).isFinished();
- }
-
- public static void finish(Object edgeEffect) {
- ((EdgeEffect) edgeEffect).finish();
- }
-
- public static boolean onPull(Object edgeEffect, float deltaDistance) {
- ((EdgeEffect) edgeEffect).onPull(deltaDistance);
- return true;
- }
-
- public static boolean onRelease(Object edgeEffect) {
- EdgeEffect eff = (EdgeEffect) edgeEffect;
- eff.onRelease();
- return eff.isFinished();
- }
-
- public static boolean onAbsorb(Object edgeEffect, int velocity) {
- ((EdgeEffect) edgeEffect).onAbsorb(velocity);
- return true;
- }
-
- public static boolean draw(Object edgeEffect, Canvas canvas) {
- return ((EdgeEffect) edgeEffect).draw(canvas);
- }
-}
\ No newline at end of file
diff --git a/compat/java/android/support/v4/graphics/PaintCompat.java b/compat/java/android/support/v4/graphics/PaintCompat.java
index 66599f7..2bc676c 100644
--- a/compat/java/android/support/v4/graphics/PaintCompat.java
+++ b/compat/java/android/support/v4/graphics/PaintCompat.java
@@ -35,9 +35,9 @@
*/
public static boolean hasGlyph(@NonNull Paint paint, @NonNull String string) {
if (Build.VERSION.SDK_INT >= 23) {
- return PaintCompatApi23.hasGlyph(paint, string);
+ return paint.hasGlyph(string);
}
- return PaintCompatGingerbread.hasGlyph(paint, string);
+ return PaintCompatApi14.hasGlyph(paint, string);
}
private PaintCompat() {}
diff --git a/compat/gingerbread/android/support/v4/os/BuildCompat.java b/compat/java/android/support/v4/os/BuildCompat.java
similarity index 92%
rename from compat/gingerbread/android/support/v4/os/BuildCompat.java
rename to compat/java/android/support/v4/os/BuildCompat.java
index b8e9d9b..6358b9e 100644
--- a/compat/gingerbread/android/support/v4/os/BuildCompat.java
+++ b/compat/java/android/support/v4/os/BuildCompat.java
@@ -29,7 +29,8 @@
/* Boilerplate for isAtLeast${PLATFORM}:
* public static boolean isAtLeast*() {
* return !"REL".equals(VERSION.CODENAME)
- * && ("${PLATFORM}".equals(VERSION.CODENAME) || VERSION.CODENAME.startsWith("${PLATFORM}MR"));
+ * && ("${PLATFORM}".equals(VERSION.CODENAME)
+ * || VERSION.CODENAME.startsWith("${PLATFORM}MR"));
* }
*/
diff --git a/compat/gingerbread/android/support/v4/view/LayoutInflaterFactory.java b/compat/java/android/support/v4/view/LayoutInflaterFactory.java
similarity index 94%
rename from compat/gingerbread/android/support/v4/view/LayoutInflaterFactory.java
rename to compat/java/android/support/v4/view/LayoutInflaterFactory.java
index 614f07f..2ee4704 100644
--- a/compat/gingerbread/android/support/v4/view/LayoutInflaterFactory.java
+++ b/compat/java/android/support/v4/view/LayoutInflaterFactory.java
@@ -43,6 +43,6 @@
* @return View Newly created view. Return null for the default
* behavior.
*/
- public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
+ View onCreateView(View parent, String name, Context context, AttributeSet attrs);
}
diff --git a/compat/gingerbread/android/support/v4/view/TintableBackgroundView.java b/compat/java/android/support/v4/view/TintableBackgroundView.java
similarity index 100%
rename from compat/gingerbread/android/support/v4/view/TintableBackgroundView.java
rename to compat/java/android/support/v4/view/TintableBackgroundView.java
diff --git a/compat/java/android/support/v4/view/ViewGroupCompat.java b/compat/java/android/support/v4/view/ViewGroupCompat.java
index 0fa76cd..39046a3 100644
--- a/compat/java/android/support/v4/view/ViewGroupCompat.java
+++ b/compat/java/android/support/v4/view/ViewGroupCompat.java
@@ -17,6 +17,7 @@
package android.support.v4.view;
import android.os.Build;
+import android.support.annotation.RequiresApi;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -43,49 +44,22 @@
*/
public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
- interface ViewGroupCompatImpl {
- boolean onRequestSendAccessibilityEvent(ViewGroup group, View child,
- AccessibilityEvent event);
- void setMotionEventSplittingEnabled(ViewGroup group, boolean split);
- int getLayoutMode(ViewGroup group);
- void setLayoutMode(ViewGroup group, int mode);
- void setTransitionGroup(ViewGroup group, boolean isTransitionGroup);
- boolean isTransitionGroup(ViewGroup group);
- int getNestedScrollAxes(ViewGroup group);
- }
-
- static class ViewGroupCompatStubImpl implements ViewGroupCompatImpl {
- @Override
- public boolean onRequestSendAccessibilityEvent(
- ViewGroup group, View child, AccessibilityEvent event) {
- return true;
- }
-
- @Override
- public void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
- // no-op, didn't exist.
- }
-
- @Override
+ static class ViewGroupCompatBaseImpl {
public int getLayoutMode(ViewGroup group) {
return LAYOUT_MODE_CLIP_BOUNDS;
}
- @Override
public void setLayoutMode(ViewGroup group, int mode) {
// no-op, didn't exist. Views only support clip bounds.
}
- @Override
public void setTransitionGroup(ViewGroup group, boolean isTransitionGroup) {
}
- @Override
public boolean isTransitionGroup(ViewGroup group) {
return false;
}
- @Override
public int getNestedScrollAxes(ViewGroup group) {
if (group instanceof NestedScrollingParent) {
return ((NestedScrollingParent) group).getNestedScrollAxes();
@@ -94,63 +68,46 @@
}
}
- static class ViewGroupCompatHCImpl extends ViewGroupCompatStubImpl {
- @Override
- public void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
- ViewGroupCompatHC.setMotionEventSplittingEnabled(group, split);
- }
- }
-
- static class ViewGroupCompatIcsImpl extends ViewGroupCompatHCImpl {
- @Override
- public boolean onRequestSendAccessibilityEvent(
- ViewGroup group, View child, AccessibilityEvent event) {
- return ViewGroupCompatIcs.onRequestSendAccessibilityEvent(group, child, event);
- }
- }
-
- static class ViewGroupCompatJellybeanMR2Impl extends ViewGroupCompatIcsImpl {
+ @RequiresApi(18)
+ static class ViewGroupCompatApi18Impl extends ViewGroupCompatBaseImpl {
@Override
public int getLayoutMode(ViewGroup group) {
- return ViewGroupCompatJellybeanMR2.getLayoutMode(group);
+ return group.getLayoutMode();
}
@Override
public void setLayoutMode(ViewGroup group, int mode) {
- ViewGroupCompatJellybeanMR2.setLayoutMode(group, mode);
+ group.setLayoutMode(mode);
}
}
- static class ViewGroupCompatLollipopImpl extends ViewGroupCompatJellybeanMR2Impl {
+ @RequiresApi(21)
+ static class ViewGroupCompatApi21Impl extends ViewGroupCompatApi18Impl {
@Override
public void setTransitionGroup(ViewGroup group, boolean isTransitionGroup) {
- ViewGroupCompatLollipop.setTransitionGroup(group, isTransitionGroup);
+ group.setTransitionGroup(isTransitionGroup);
}
@Override
public boolean isTransitionGroup(ViewGroup group) {
- return ViewGroupCompatLollipop.isTransitionGroup(group);
+ return group.isTransitionGroup();
}
@Override
public int getNestedScrollAxes(ViewGroup group) {
- return ViewGroupCompatLollipop.getNestedScrollAxes(group);
+ return group.getNestedScrollAxes();
}
}
- static final ViewGroupCompatImpl IMPL;
+ static final ViewGroupCompatBaseImpl IMPL;
static {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
- IMPL = new ViewGroupCompatLollipopImpl();
+ IMPL = new ViewGroupCompatApi21Impl();
} else if (version >= 18) {
- IMPL = new ViewGroupCompatJellybeanMR2Impl();
- } else if (version >= 14) {
- IMPL = new ViewGroupCompatIcsImpl();
- } else if (version >= 11) {
- IMPL = new ViewGroupCompatHCImpl();
+ IMPL = new ViewGroupCompatApi18Impl();
} else {
- IMPL = new ViewGroupCompatStubImpl();
+ IMPL = new ViewGroupCompatBaseImpl();
}
}
@@ -173,10 +130,14 @@
* @param child The child which requests sending the event.
* @param event The event to be sent.
* @return True if the event should be sent.
+ *
+ * @deprecated Use {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)}
+ * directly.
*/
+ @Deprecated
public static boolean onRequestSendAccessibilityEvent(ViewGroup group, View child,
AccessibilityEvent event) {
- return IMPL.onRequestSendAccessibilityEvent(group, child, event);
+ return group.onRequestSendAccessibilityEvent(child, event);
}
/**
@@ -194,9 +155,12 @@
* @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
* child views. <code>false</code> to only allow one child view to be the target of
* any MotionEvent received by this ViewGroup.
+ *
+ * @deprecated Use {@link ViewGroup#setMotionEventSplittingEnabled(boolean)} directly.
*/
+ @Deprecated
public static void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
- IMPL.setMotionEventSplittingEnabled(group, split);
+ group.setMotionEventSplittingEnabled(split);
}
/**
diff --git a/compat/java/android/support/v4/view/ViewParentCompat.java b/compat/java/android/support/v4/view/ViewParentCompat.java
index ec97988..53ff8dd 100644
--- a/compat/java/android/support/v4/view/ViewParentCompat.java
+++ b/compat/java/android/support/v4/view/ViewParentCompat.java
@@ -16,15 +16,15 @@
package android.support.v4.view;
-import android.content.Context;
import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
/**
* Helper for accessing features in {@link ViewParent}
@@ -32,39 +32,9 @@
*/
public final class ViewParentCompat {
- interface ViewParentCompatImpl {
- public boolean requestSendAccessibilityEvent(
- ViewParent parent, View child, AccessibilityEvent event);
- boolean onStartNestedScroll(ViewParent parent, View child, View target,
- int nestedScrollAxes);
- void onNestedScrollAccepted(ViewParent parent, View child, View target,
- int nestedScrollAxes);
- void onStopNestedScroll(ViewParent parent, View target);
- void onNestedScroll(ViewParent parent, View target, int dxConsumed, int dyConsumed,
- int dxUnconsumed, int dyUnconsumed);
- void onNestedPreScroll(ViewParent parent, View target, int dx, int dy, int[] consumed);
- boolean onNestedFling(ViewParent parent, View target, float velocityX, float velocityY,
- boolean consumed);
- boolean onNestedPreFling(ViewParent parent, View target, float velocityX, float velocityY);
- void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
- View source, int changeType);
- }
+ private static final String TAG = "ViewParentCompat";
- static class ViewParentCompatStubImpl implements ViewParentCompatImpl {
- @Override
- public boolean requestSendAccessibilityEvent(
- ViewParent parent, View child, AccessibilityEvent event) {
- // Emulate what ViewRootImpl does in ICS and above.
- if (child == null) {
- return false;
- }
- final AccessibilityManager manager = (AccessibilityManager) child.getContext()
- .getSystemService(Context.ACCESSIBILITY_SERVICE);
- manager.sendAccessibilityEvent(event);
- return true;
- }
-
- @Override
+ static class ViewParentCompatBaseImpl {
public boolean onStartNestedScroll(ViewParent parent, View child, View target,
int nestedScrollAxes) {
if (parent instanceof NestedScrollingParent) {
@@ -74,7 +44,6 @@
return false;
}
- @Override
public void onNestedScrollAccepted(ViewParent parent, View child, View target,
int nestedScrollAxes) {
if (parent instanceof NestedScrollingParent) {
@@ -83,14 +52,12 @@
}
}
- @Override
public void onStopNestedScroll(ViewParent parent, View target) {
if (parent instanceof NestedScrollingParent) {
((NestedScrollingParent) parent).onStopNestedScroll(target);
}
}
- @Override
public void onNestedScroll(ViewParent parent, View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
if (parent instanceof NestedScrollingParent) {
@@ -99,7 +66,6 @@
}
}
- @Override
public void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
int[] consumed) {
if (parent instanceof NestedScrollingParent) {
@@ -107,7 +73,6 @@
}
}
- @Override
public boolean onNestedFling(ViewParent parent, View target, float velocityX,
float velocityY, boolean consumed) {
if (parent instanceof NestedScrollingParent) {
@@ -117,7 +82,6 @@
return false;
}
- @Override
public boolean onNestedPreFling(ViewParent parent, View target, float velocityX,
float velocityY) {
if (parent instanceof NestedScrollingParent) {
@@ -127,88 +91,112 @@
return false;
}
- @Override
public void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
View source, int changeType) {
}
}
- static class ViewParentCompatICSImpl extends ViewParentCompatStubImpl {
- @Override
- public boolean requestSendAccessibilityEvent(
- ViewParent parent, View child, AccessibilityEvent event) {
- return ViewParentCompatICS.requestSendAccessibilityEvent(parent, child, event);
- }
- }
-
- static class ViewParentCompatKitKatImpl extends ViewParentCompatICSImpl {
+ @RequiresApi(19)
+ static class ViewParentCompatApi19Impl extends ViewParentCompatBaseImpl {
@Override
public void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
View source, int changeType) {
- ViewParentCompatKitKat.notifySubtreeAccessibilityStateChanged(parent, child,
- source, changeType);
+ parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);
}
}
- static class ViewParentCompatLollipopImpl extends ViewParentCompatKitKatImpl {
+ @RequiresApi(21)
+ static class ViewParentCompatApi21Impl extends ViewParentCompatApi19Impl {
@Override
public boolean onStartNestedScroll(ViewParent parent, View child, View target,
int nestedScrollAxes) {
- return ViewParentCompatLollipop.onStartNestedScroll(parent, child, target,
- nestedScrollAxes);
+ try {
+ return parent.onStartNestedScroll(child, target, nestedScrollAxes);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ + "method onStartNestedScroll", e);
+ return false;
+ }
}
@Override
public void onNestedScrollAccepted(ViewParent parent, View child, View target,
int nestedScrollAxes) {
- ViewParentCompatLollipop.onNestedScrollAccepted(parent, child, target,
- nestedScrollAxes);
+ try {
+ parent.onNestedScrollAccepted(child, target, nestedScrollAxes);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ + "method onNestedScrollAccepted", e);
+ }
}
@Override
public void onStopNestedScroll(ViewParent parent, View target) {
- ViewParentCompatLollipop.onStopNestedScroll(parent, target);
+ try {
+ parent.onStopNestedScroll(target);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ + "method onStopNestedScroll", e);
+ }
}
@Override
public void onNestedScroll(ViewParent parent, View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
- ViewParentCompatLollipop.onNestedScroll(parent, target, dxConsumed, dyConsumed,
- dxUnconsumed, dyUnconsumed);
+ try {
+ parent.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ + "method onNestedScroll", e);
+ }
}
@Override
public void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
int[] consumed) {
- ViewParentCompatLollipop.onNestedPreScroll(parent, target, dx, dy, consumed);
+ try {
+ parent.onNestedPreScroll(target, dx, dy, consumed);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ + "method onNestedPreScroll", e);
+ }
}
@Override
public boolean onNestedFling(ViewParent parent, View target, float velocityX,
float velocityY, boolean consumed) {
- return ViewParentCompatLollipop.onNestedFling(parent, target, velocityX, velocityY,
- consumed);
+ try {
+ return parent.onNestedFling(target, velocityX, velocityY, consumed);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ + "method onNestedFling", e);
+ return false;
+ }
}
@Override
public boolean onNestedPreFling(ViewParent parent, View target, float velocityX,
float velocityY) {
- return ViewParentCompatLollipop.onNestedPreFling(parent, target, velocityX, velocityY);
+ try {
+ return parent.onNestedPreFling(target, velocityX, velocityY);
+ } catch (AbstractMethodError e) {
+ Log.e(TAG, "ViewParent " + parent + " does not implement interface "
+ + "method onNestedPreFling", e);
+ return false;
+ }
}
}
- static final ViewParentCompatImpl IMPL;
+ static final ViewParentCompatBaseImpl IMPL;
static {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
- IMPL = new ViewParentCompatLollipopImpl();
+ IMPL = new ViewParentCompatApi21Impl();
} else if (version >= 19) {
- IMPL = new ViewParentCompatKitKatImpl();
- } else if (version >= 14) {
- IMPL = new ViewParentCompatICSImpl();
+ IMPL = new ViewParentCompatApi19Impl();
} else {
- IMPL = new ViewParentCompatStubImpl();
+ IMPL = new ViewParentCompatBaseImpl();
}
}
@@ -233,10 +221,14 @@
* @param child The child which requests sending the event.
* @param event The event to be sent.
* @return True if the event was sent.
+ *
+ * @deprecated Use {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
+ * directly.
*/
+ @Deprecated
public static boolean requestSendAccessibilityEvent(
ViewParent parent, View child, AccessibilityEvent event) {
- return IMPL.requestSendAccessibilityEvent(parent, child, event);
+ return parent.requestSendAccessibilityEvent(child, event);
}
/**
diff --git a/compat/java/android/support/v4/widget/EdgeEffectCompat.java b/compat/java/android/support/v4/widget/EdgeEffectCompat.java
index d65fb67..8be2d9f 100644
--- a/compat/java/android/support/v4/widget/EdgeEffectCompat.java
+++ b/compat/java/android/support/v4/widget/EdgeEffectCompat.java
@@ -18,142 +18,41 @@
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.widget.EdgeEffect;
/**
- * Helper for accessing {@link android.widget.EdgeEffect} introduced after
- * API level 4 in a backwards compatible fashion.
+ * Helper for accessing {@link android.widget.EdgeEffect} in a backwards compatible fashion.
*
- * This class is used to access {@link android.widget.EdgeEffect} on platform versions
- * that support it. When running on older platforms it will result in no-ops. It should
- * be used by views that wish to use the standard Android visual effects at the edges
+ * This class is used to access {@link android.widget.EdgeEffect} on platform versions
+ * that support it. When running on older platforms it will result in no-ops. It should
+ * be used by views that wish to use the standard Android visual effects at the edges
* of scrolling containers.
*/
public final class EdgeEffectCompat {
- private Object mEdgeEffect;
+ private EdgeEffect mEdgeEffect;
- private static final EdgeEffectImpl IMPL;
+ private static final EdgeEffectBaseImpl IMPL;
static {
if (Build.VERSION.SDK_INT >= 21) {
- IMPL = new EdgeEffectLollipopImpl(); // Lollipop
- } else if (Build.VERSION.SDK_INT >= 14) { // ICS
- IMPL = new EdgeEffectIcsImpl();
+ IMPL = new EdgeEffectApi21Impl();
} else {
- IMPL = new BaseEdgeEffectImpl();
+ IMPL = new EdgeEffectBaseImpl();
}
}
- interface EdgeEffectImpl {
- public Object newEdgeEffect(Context context);
- public void setSize(Object edgeEffect, int width, int height);
- public boolean isFinished(Object edgeEffect);
- public void finish(Object edgeEffect);
- public boolean onPull(Object edgeEffect, float deltaDistance);
- public boolean onRelease(Object edgeEffect);
- public boolean onAbsorb(Object edgeEffect, int velocity);
- public boolean draw(Object edgeEffect, Canvas canvas);
- public boolean onPull(Object edgeEffect, float deltaDistance, float displacement);
- }
-
- /**
- * Null implementation to use pre-ICS
- */
- static class BaseEdgeEffectImpl implements EdgeEffectImpl {
- @Override
- public Object newEdgeEffect(Context context) {
- return null;
- }
-
- @Override
- public void setSize(Object edgeEffect, int width, int height) {
- }
-
- @Override
- public boolean isFinished(Object edgeEffect) {
- return true;
- }
-
- @Override
- public void finish(Object edgeEffect) {
- }
-
- @Override
- public boolean onPull(Object edgeEffect, float deltaDistance) {
- return false;
- }
-
- @Override
- public boolean onRelease(Object edgeEffect) {
- return false;
- }
-
- @Override
- public boolean onAbsorb(Object edgeEffect, int velocity) {
- return false;
- }
-
- @Override
- public boolean draw(Object edgeEffect, Canvas canvas) {
- return false;
- }
-
- @Override
- public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
- return false;
+ static class EdgeEffectBaseImpl {
+ public void onPull(EdgeEffect edgeEffect, float deltaDistance, float displacement) {
+ edgeEffect.onPull(deltaDistance);
}
}
- static class EdgeEffectIcsImpl implements EdgeEffectImpl {
+ @RequiresApi(21)
+ static class EdgeEffectApi21Impl extends EdgeEffectBaseImpl {
@Override
- public Object newEdgeEffect(Context context) {
- return EdgeEffectCompatIcs.newEdgeEffect(context);
- }
-
- @Override
- public void setSize(Object edgeEffect, int width, int height) {
- EdgeEffectCompatIcs.setSize(edgeEffect, width, height);
- }
-
- @Override
- public boolean isFinished(Object edgeEffect) {
- return EdgeEffectCompatIcs.isFinished(edgeEffect);
- }
-
- @Override
- public void finish(Object edgeEffect) {
- EdgeEffectCompatIcs.finish(edgeEffect);
- }
-
- @Override
- public boolean onPull(Object edgeEffect, float deltaDistance) {
- return EdgeEffectCompatIcs.onPull(edgeEffect, deltaDistance);
- }
-
- @Override
- public boolean onRelease(Object edgeEffect) {
- return EdgeEffectCompatIcs.onRelease(edgeEffect);
- }
-
- @Override
- public boolean onAbsorb(Object edgeEffect, int velocity) {
- return EdgeEffectCompatIcs.onAbsorb(edgeEffect, velocity);
- }
-
- @Override
- public boolean draw(Object edgeEffect, Canvas canvas) {
- return EdgeEffectCompatIcs.draw(edgeEffect, canvas);
- }
-
- @Override
- public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
- return EdgeEffectCompatIcs.onPull(edgeEffect, deltaDistance);
- }
- }
-
- static class EdgeEffectLollipopImpl extends EdgeEffectIcsImpl {
- @Override
- public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) {
- return EdgeEffectCompatLollipop.onPull(edgeEffect, deltaDistance, displacement);
+ public void onPull(EdgeEffect edgeEffect, float deltaDistance, float displacement) {
+ edgeEffect.onPull(deltaDistance, displacement);
}
}
@@ -164,9 +63,12 @@
* on the newly constructed object will be mocked/no-ops.</p>
*
* @param context Context to use for theming the effect
+ *
+ * @deprecated Use {@link EdgeEffect} constructor directly.
*/
+ @Deprecated
public EdgeEffectCompat(Context context) {
- mEdgeEffect = IMPL.newEdgeEffect(context);
+ mEdgeEffect = new EdgeEffect(context);
}
/**
@@ -174,9 +76,12 @@
*
* @param width Effect width in pixels
* @param height Effect height in pixels
+ *
+ * @deprecated Use {@link EdgeEffect#setSize(int, int)} directly.
*/
+ @Deprecated
public void setSize(int width, int height) {
- IMPL.setSize(mEdgeEffect, width, height);
+ mEdgeEffect.setSize(width, height);
}
/**
@@ -185,17 +90,23 @@
* drawing pass to continue the animation.
*
* @return true if animation is finished, false if drawing should continue on the next frame.
+ *
+ * @deprecated Use {@link EdgeEffect#isFinished()} directly.
*/
+ @Deprecated
public boolean isFinished() {
- return IMPL.isFinished(mEdgeEffect);
+ return mEdgeEffect.isFinished();
}
/**
* Immediately finish the current animation.
* After this call {@link #isFinished()} will return true.
+ *
+ * @deprecated Use {@link EdgeEffect#finish()} directly.
*/
+ @Deprecated
public void finish() {
- IMPL.finish(mEdgeEffect);
+ mEdgeEffect.finish();
}
/**
@@ -208,11 +119,13 @@
* 1.f (full length of the view) or negative values to express change
* back toward the edge reached to initiate the effect.
* @return true if the host view should call invalidate, false if it should not.
- * @deprecated use {@link #onPull(float, float)}
+ *
+ * @deprecated Use {@link #onPull(EdgeEffect, float, float)}.
*/
@Deprecated
public boolean onPull(float deltaDistance) {
- return IMPL.onPull(mEdgeEffect, deltaDistance);
+ mEdgeEffect.onPull(deltaDistance);
+ return true;
}
/**
@@ -221,6 +134,9 @@
* The host view should always {@link android.view.View#invalidate()} if this method
* returns true and draw the results accordingly.
*
+ * Views using {@link EdgeEffect} should favor {@link EdgeEffect#onPull(float, float)} when
+ * the displacement of the pull point is known.
+ *
* @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
* 1.f (full length of the view) or negative values to express change
* back toward the edge reached to initiate the effect.
@@ -228,9 +144,34 @@
* initiating the pull. In the case of touch this is the finger position.
* Values may be from 0-1.
* @return true if the host view should call invalidate, false if it should not.
+ *
+ * @deprecated Use {@link EdgeEffect#onPull(float)} directly.
*/
+ @Deprecated
public boolean onPull(float deltaDistance, float displacement) {
- return IMPL.onPull(mEdgeEffect, deltaDistance, displacement);
+ IMPL.onPull(mEdgeEffect, deltaDistance, displacement);
+ return true;
+ }
+
+ /**
+ * A view should call this when content is pulled away from an edge by the user.
+ * This will update the state of the current visual effect and its associated animation.
+ * The host view should always {@link android.view.View#invalidate()} after call this method
+ * and draw the results accordingly.
+ *
+ * @param edgeEffect The EdgeEffect that is attached to the view that is getting pulled away
+ * from an edge by the user.
+ * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+ * 1.f (full length of the view) or negative values to express change
+ * back toward the edge reached to initiate the effect.
+ * @param displacement The displacement from the starting side of the effect of the point
+ * initiating the pull. In the case of touch this is the finger position.
+ * Values may be from 0-1.
+ *
+ * @see {@link EdgeEffect#onPull(float, float)}
+ */
+ public static void onPull(EdgeEffect edgeEffect, float deltaDistance, float displacement) {
+ IMPL.onPull(edgeEffect, deltaDistance, displacement);
}
/**
@@ -240,9 +181,13 @@
* returns true and thereby draw the results accordingly.
*
* @return true if the host view should invalidate, false if it should not.
+ *
+ * @deprecated Use {@link EdgeEffect#onRelease()} directly.
*/
+ @Deprecated
public boolean onRelease() {
- return IMPL.onRelease(mEdgeEffect);
+ mEdgeEffect.onRelease();
+ return mEdgeEffect.isFinished();
}
/**
@@ -255,9 +200,13 @@
*
* @param velocity Velocity at impact in pixels per second.
* @return true if the host view should invalidate, false if it should not.
+ *
+ * @deprecated Use {@link EdgeEffect#onAbsorb(int)} directly.
*/
+ @Deprecated
public boolean onAbsorb(int velocity) {
- return IMPL.onAbsorb(mEdgeEffect, velocity);
+ mEdgeEffect.onAbsorb(velocity);
+ return true;
}
/**
@@ -269,8 +218,11 @@
* @param canvas Canvas to draw into
* @return true if drawing should continue beyond this frame to continue the
* animation
+ *
+ * @deprecated Use {@link EdgeEffect#draw(Canvas)} directly.
*/
+ @Deprecated
public boolean draw(Canvas canvas) {
- return IMPL.draw(mEdgeEffect, canvas);
+ return mEdgeEffect.draw(canvas);
}
}
diff --git a/compat/gingerbread/android/support/v4/widget/TintableCompoundButton.java b/compat/java/android/support/v4/widget/TintableCompoundButton.java
similarity index 86%
rename from compat/gingerbread/android/support/v4/widget/TintableCompoundButton.java
rename to compat/java/android/support/v4/widget/TintableCompoundButton.java
index 6bcfa30..f739fac 100644
--- a/compat/gingerbread/android/support/v4/widget/TintableCompoundButton.java
+++ b/compat/java/android/support/v4/widget/TintableCompoundButton.java
@@ -37,7 +37,7 @@
*
* @param tint the tint to apply, may be {@code null} to clear tint
*/
- public void setSupportButtonTintList(@Nullable ColorStateList tint);
+ void setSupportButtonTintList(@Nullable ColorStateList tint);
/**
* Returns the tint applied to the button drawable
@@ -45,7 +45,7 @@
* @see #setSupportButtonTintList(ColorStateList)
*/
@Nullable
- public ColorStateList getSupportButtonTintList();
+ ColorStateList getSupportButtonTintList();
/**
* Specifies the blending mode which should be used to apply the tint specified by
@@ -56,9 +56,10 @@
* {@code null} to clear tint
*
* @see #getSupportButtonTintMode()
- * @see DrawableCompat#setTintMode(Drawable, PorterDuff.Mode)
+ * @see android.support.v4.graphics.drawable.DrawableCompat#setTintMode(Drawable,
+ * PorterDuff.Mode)
*/
- public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode);
+ void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode);
/**
* Returns the blending mode used to apply the tint to the button drawable
@@ -66,5 +67,5 @@
* @see #setSupportButtonTintMode(PorterDuff.Mode)
*/
@Nullable
- public PorterDuff.Mode getSupportButtonTintMode();
+ PorterDuff.Mode getSupportButtonTintMode();
}
diff --git a/compat/jellybean-mr2/android/support/v4/view/ViewGroupCompatJellybeanMR2.java b/compat/jellybean-mr2/android/support/v4/view/ViewGroupCompatJellybeanMR2.java
deleted file mode 100644
index 184ef6c..0000000
--- a/compat/jellybean-mr2/android/support/v4/view/ViewGroupCompatJellybeanMR2.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2013 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.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.view.ViewGroup;
-
-@RequiresApi(18)
-class ViewGroupCompatJellybeanMR2 {
- public static int getLayoutMode(ViewGroup group) {
- return group.getLayoutMode();
- }
-
- public static void setLayoutMode(ViewGroup group, int mode) {
- group.setLayoutMode(mode);
- }
-}
diff --git a/compat/kitkat/android/support/v4/view/ViewParentCompatKitKat.java b/compat/kitkat/android/support/v4/view/ViewParentCompatKitKat.java
deleted file mode 100644
index 78761a4..0000000
--- a/compat/kitkat/android/support/v4/view/ViewParentCompatKitKat.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.v4.view;
-
-import android.support.annotation.RequiresApi;
-import android.view.View;
-import android.view.ViewParent;
-
-@RequiresApi(19)
-class ViewParentCompatKitKat {
- public static void notifySubtreeAccessibilityStateChanged(ViewParent parent, View child,
- View source, int changeType) {
- parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);
- }
-}
diff --git a/core-ui/java/android/support/v4/view/ViewPager.java b/core-ui/java/android/support/v4/view/ViewPager.java
index 2615cd2..7ac7106 100644
--- a/core-ui/java/android/support/v4/view/ViewPager.java
+++ b/core-ui/java/android/support/v4/view/ViewPager.java
@@ -37,7 +37,6 @@
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
-import android.support.v4.widget.EdgeEffectCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
@@ -52,6 +51,7 @@
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Interpolator;
+import android.widget.EdgeEffect;
import android.widget.Scroller;
import java.lang.annotation.ElementType;
@@ -225,8 +225,8 @@
private boolean mFakeDragging;
private long mFakeDragBeginTime;
- private EdgeEffectCompat mLeftEdge;
- private EdgeEffectCompat mRightEdge;
+ private EdgeEffect mLeftEdge;
+ private EdgeEffect mRightEdge;
private boolean mFirstLayout = true;
private boolean mNeedCalculatePageOffsets = false;
@@ -406,8 +406,8 @@
mTouchSlop = configuration.getScaledPagingTouchSlop();
mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
- mLeftEdge = new EdgeEffectCompat(context);
- mRightEdge = new EdgeEffectCompat(context);
+ mLeftEdge = new EdgeEffect(context);
+ mRightEdge = new EdgeEffect(context);
mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
mCloseEnough = (int) (CLOSE_ENOUGH * density);
@@ -2284,7 +2284,9 @@
boolean needsInvalidate;
mActivePointerId = INVALID_POINTER;
endDrag();
- needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+ mLeftEdge.onRelease();
+ mRightEdge.onRelease();
+ needsInvalidate = mLeftEdge.isFinished() | mRightEdge.isFinished();
return needsInvalidate;
}
@@ -2324,13 +2326,15 @@
if (scrollX < leftBound) {
if (leftAbsolute) {
float over = leftBound - scrollX;
- needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width);
+ mLeftEdge.onPull(Math.abs(over) / width);
+ needsInvalidate = true;
}
scrollX = leftBound;
} else if (scrollX > rightBound) {
if (rightAbsolute) {
float over = scrollX - rightBound;
- needsInvalidate = mRightEdge.onPull(Math.abs(over) / width);
+ mRightEdge.onPull(Math.abs(over) / width);
+ needsInvalidate = true;
}
scrollX = rightBound;
}
diff --git a/core-ui/java/android/support/v4/widget/NestedScrollView.java b/core-ui/java/android/support/v4/widget/NestedScrollView.java
index 2cfd551..2bc09d1 100644
--- a/core-ui/java/android/support/v4/widget/NestedScrollView.java
+++ b/core-ui/java/android/support/v4/widget/NestedScrollView.java
@@ -51,6 +51,7 @@
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
+import android.widget.EdgeEffect;
import android.widget.FrameLayout;
import android.widget.ScrollView;
@@ -95,8 +96,8 @@
private final Rect mTempRect = new Rect();
private ScrollerCompat mScroller;
- private EdgeEffectCompat mEdgeGlowTop;
- private EdgeEffectCompat mEdgeGlowBottom;
+ private EdgeEffect mEdgeGlowTop;
+ private EdgeEffect mEdgeGlowBottom;
/**
* Position of the last motion event.
@@ -808,13 +809,13 @@
ensureGlows();
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
- mEdgeGlowTop.onPull((float) deltaY / getHeight(),
+ EdgeEffectCompat.onPull(mEdgeGlowTop, (float) deltaY / getHeight(),
ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
} else if (pulledToY > range) {
- mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
+ EdgeEffectCompat.onPull(mEdgeGlowBottom, (float) deltaY / getHeight(),
1.f - ev.getX(activePointerIndex)
/ getWidth());
if (!mEdgeGlowTop.isFinished()) {
@@ -1749,8 +1750,8 @@
if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
if (mEdgeGlowTop == null) {
Context context = getContext();
- mEdgeGlowTop = new EdgeEffectCompat(context);
- mEdgeGlowBottom = new EdgeEffectCompat(context);
+ mEdgeGlowTop = new EdgeEffect(context);
+ mEdgeGlowBottom = new EdgeEffect(context);
}
} else {
mEdgeGlowTop = null;
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
index 2db3471..1ade508 100644
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
@@ -24,8 +24,10 @@
import android.os.Build;
import android.os.SystemClock;
import android.support.design.test.R;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.LargeTest;
import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.Suppress;
import android.widget.ImageView;
import org.junit.Test;
@@ -137,6 +139,8 @@
assertScrimAlpha(0);
}
+ @Suppress
+ @FlakyTest(bugId = 30701044)
@Test
public void testScrollingToolbar() throws Throwable {
configureContent(R.layout.design_appbar_toolbar_collapse_scroll,
@@ -247,6 +251,8 @@
assertScrimAlpha(0);
}
+ @Suppress
+ @FlakyTest(bugId = 30701044)
@Test
public void testScrollingToolbarEnterAlways() throws Throwable {
configureContent(R.layout.design_appbar_toolbar_collapse_scroll_enteralways,
@@ -352,6 +358,8 @@
assertScrimAlpha(0);
}
+ @Suppress
+ @FlakyTest(bugId = 30701044)
@Test
public void testPinnedToolbarAndAnchoredFab() throws Throwable {
configureContent(R.layout.design_appbar_toolbar_collapse_pin_with_fab,
@@ -418,6 +426,8 @@
}
}
+ @Suppress
+ @FlakyTest(bugId = 30701044)
@Test
public void testPinnedToolbarAndParallaxImage() throws Throwable {
configureContent(R.layout.design_appbar_toolbar_collapse_with_image,
@@ -521,6 +531,8 @@
* inherits from) has an issue with measuring children with margins when run on earlier
* versions of the platform.
*/
+ @Suppress
+ @FlakyTest(bugId = 30701044)
@Test
@SdkSuppress(minSdkVersion = 11)
public void testPinnedToolbarWithMargins() throws Throwable {
diff --git a/media-compat/java/android/support/v4/media/MediaDescriptionCompat.aidl b/media-compat/java/android/support/v4/media/MediaDescriptionCompat.aidl
new file mode 100644
index 0000000..f002cdd
--- /dev/null
+++ b/media-compat/java/android/support/v4/media/MediaDescriptionCompat.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2017, 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.v4.media;
+
+parcelable MediaDescriptionCompat;
diff --git a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
index 4f2e38a..969b803 100644
--- a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
+++ b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
@@ -17,6 +17,7 @@
import android.app.PendingIntent;
import android.content.Intent;
+import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.RatingCompat;
import android.support.v4.media.session.IMediaControllerCallback;
@@ -33,7 +34,7 @@
* @hide
*/
interface IMediaSession {
- // Next ID: 40
+ // Next ID: 44
void sendCommand(String command, in Bundle args, in MediaSessionCompat.ResultReceiverWrapper cb) = 0;
boolean sendMediaButton(in KeyEvent mediaButton) = 1;
void registerCallbackListener(in IMediaControllerCallback cb) = 2;
@@ -54,6 +55,10 @@
int getRatingType() = 31;
int getRepeatMode() = 36;
boolean isShuffleModeEnabled() = 37;
+ void addQueueItem(in MediaDescriptionCompat description) = 40;
+ void addQueueItemAt(in MediaDescriptionCompat description, int index) = 41;
+ void removeQueueItem(in MediaDescriptionCompat description) = 42;
+ void removeQueueItemAt(int index) = 43;
// These commands are for the TransportControls
void prepare() = 32;
diff --git a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
index 94030bc..5c80db1 100644
--- a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -30,6 +30,7 @@
import android.os.ResultReceiver;
import android.support.v4.app.BundleCompat;
import android.support.v4.app.SupportActivity;
+import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.RatingCompat;
import android.support.v4.media.VolumeProviderCompat;
@@ -62,6 +63,19 @@
static final String COMMAND_GET_EXTRA_BINDER =
"android.support.v4.media.session.command.GET_EXTRA_BINDER";
+ static final String COMMAND_ADD_QUEUE_ITEM =
+ "android.support.v4.media.session.command.ADD_QUEUE_ITEM";
+ static final String COMMAND_ADD_QUEUE_ITEM_AT =
+ "android.support.v4.media.session.command.ADD_QUEUE_ITEM_AT";
+ static final String COMMAND_REMOVE_QUEUE_ITEM =
+ "android.support.v4.media.session.command.REMOVE_QUEUE_ITEM";
+ static final String COMMAND_REMOVE_QUEUE_ITEM_AT =
+ "android.support.v4.media.session.command.REMOVE_QUEUE_ITEM_AT";
+
+ static final String COMMAND_ARGUMENT_MEDIA_DESCRIPTION =
+ "android.support.v4.media.session.command.ARGUMENT_MEDIA_DESCRIPTION";
+ static final String COMMAND_ARGUMENT_INDEX =
+ "android.support.v4.media.session.command.ARGUMENT_INDEX";
private static class MediaControllerExtraData extends SupportActivity.ExtraData {
private final MediaControllerCompat mMediaController;
@@ -241,6 +255,62 @@
}
/**
+ * Add a queue item from the given {@code description} at the end of the play queue
+ * of this session. Not all sessions may support this.
+ *
+ * @param description The {@link MediaDescriptionCompat} for creating the
+ * {@link MediaSessionCompat.QueueItem} to be inserted.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void addQueueItem(MediaDescriptionCompat description) {
+ mImpl.addQueueItem(description);
+ }
+
+ /**
+ * Add a queue item from the given {@code description} at the specified position
+ * in the play queue of this session. Shifts the queue item currently at that position
+ * (if any) and any subsequent queue items to the right (adds one to their indices).
+ * Not all sessions may support this.
+ *
+ * @param description The {@link MediaDescriptionCompat} for creating the
+ * {@link MediaSessionCompat.QueueItem} to be inserted.
+ * @param index The index at which the created {@link MediaSessionCompat.QueueItem}
+ * is to be inserted.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void addQueueItem(MediaDescriptionCompat description, int index) {
+ mImpl.addQueueItem(description, index);
+ }
+
+ /**
+ * Remove the first occurrence of the specified {@link MediaSessionCompat.QueueItem}
+ * with the given {@link MediaDescriptionCompat description} in the play queue of the
+ * associated session. Not all sessions may support this.
+ *
+ * @param description The {@link MediaDescriptionCompat} for denoting the
+ * {@link MediaSessionCompat.QueueItem} to be removed.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void removeQueueItem(MediaDescriptionCompat description) {
+ mImpl.removeQueueItem(description);
+ }
+
+ /**
+ * Remove an queue item at the specified position in the play queue
+ * of this session. Not all sessions may support this.
+ *
+ * @param index The index of the element to be removed.
+ * @throws UnsupportedOperationException If this session doesn't support this.
+ * @see MediaSessionCompat#FLAG_HANDLES_QUEUE_COMMANDS
+ */
+ public void removeQueueItemAt(int index) {
+ mImpl.removeQueueItemAt(index);
+ }
+
+ /**
* Get the queue title for this session.
*/
public CharSequence getQueueTitle() {
@@ -1051,6 +1121,10 @@
MediaMetadataCompat getMetadata();
List<MediaSessionCompat.QueueItem> getQueue();
+ void addQueueItem(MediaDescriptionCompat description);
+ void addQueueItem(MediaDescriptionCompat description, int index);
+ void removeQueueItem(MediaDescriptionCompat description);
+ void removeQueueItemAt(int index);
CharSequence getQueueTitle();
Bundle getExtras();
int getRatingType();
@@ -1162,6 +1236,62 @@
}
@Override
+ public void addQueueItem(MediaDescriptionCompat description) {
+ try {
+ long flags = mBinder.getFlags();
+ if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mBinder.addQueueItem(description);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in addQueueItem. " + e);
+ }
+ }
+
+ @Override
+ public void addQueueItem(MediaDescriptionCompat description, int index) {
+ try {
+ long flags = mBinder.getFlags();
+ if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mBinder.addQueueItemAt(description, index);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in addQueueItemAt. " + e);
+ }
+ }
+
+ @Override
+ public void removeQueueItem(MediaDescriptionCompat description) {
+ try {
+ long flags = mBinder.getFlags();
+ if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mBinder.removeQueueItem(description);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in removeQueueItem. " + e);
+ }
+ }
+
+ @Override
+ public void removeQueueItemAt(int index) {
+ try {
+ long flags = mBinder.getFlags();
+ if ((flags & MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS) == 0) {
+ throw new UnsupportedOperationException(
+ "This session doesn't support queue management operations");
+ }
+ mBinder.removeQueueItemAt(index);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in removeQueueItemAt. " + e);
+ }
+ }
+
+ @Override
public CharSequence getQueueTitle() {
try {
return mBinder.getQueueTitle();
@@ -1589,6 +1719,35 @@
}
@Override
+ public void addQueueItem(MediaDescriptionCompat description) {
+ Bundle params = new Bundle();
+ params.putParcelable(COMMAND_ARGUMENT_MEDIA_DESCRIPTION, description);
+ sendCommand(COMMAND_ADD_QUEUE_ITEM, params, null);
+ }
+
+ @Override
+ public void addQueueItem(MediaDescriptionCompat description, int index) {
+ Bundle params = new Bundle();
+ params.putParcelable(COMMAND_ARGUMENT_MEDIA_DESCRIPTION, description);
+ params.putInt(COMMAND_ARGUMENT_INDEX, index);
+ sendCommand(COMMAND_ADD_QUEUE_ITEM_AT, params, null);
+ }
+
+ @Override
+ public void removeQueueItem(MediaDescriptionCompat description) {
+ Bundle params = new Bundle();
+ params.putParcelable(COMMAND_ARGUMENT_MEDIA_DESCRIPTION, description);
+ sendCommand(COMMAND_REMOVE_QUEUE_ITEM, params, null);
+ }
+
+ @Override
+ public void removeQueueItemAt(int index) {
+ Bundle params = new Bundle();
+ params.putInt(COMMAND_ARGUMENT_INDEX, index);
+ sendCommand(COMMAND_REMOVE_QUEUE_ITEM_AT, params, null);
+ }
+
+ @Override
public CharSequence getQueueTitle() {
return MediaControllerCompatApi21.getQueueTitle(mControllerObj);
}
diff --git a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
index 4d929a4..c588c7b 100644
--- a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -100,7 +100,10 @@
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
- @IntDef(flag=true, value={FLAG_HANDLES_MEDIA_BUTTONS, FLAG_HANDLES_TRANSPORT_CONTROLS})
+ @IntDef(flag=true, value={
+ FLAG_HANDLES_MEDIA_BUTTONS,
+ FLAG_HANDLES_TRANSPORT_CONTROLS,
+ FLAG_HANDLES_QUEUE_COMMANDS })
@Retention(RetentionPolicy.SOURCE)
public @interface SessionFlags {}
@@ -117,6 +120,12 @@
public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
/**
+ * Set this flag on the session to indicate that it handles queue
+ * management commands through its {@link Callback}.
+ */
+ public static final int FLAG_HANDLES_QUEUE_COMMANDS = 1 << 2;
+
+ /**
* Custom action to invoke playFromUri() for the forward compatibility.
*/
static final String ACTION_PLAY_FROM_URI =
@@ -277,8 +286,6 @@
mImpl = new MediaSessionImplApi19(context, tag, mbrComponent, mbrIntent);
} else if (android.os.Build.VERSION.SDK_INT >= 18) {
mImpl = new MediaSessionImplApi18(context, tag, mbrComponent, mbrIntent);
- } else if (android.os.Build.VERSION.SDK_INT >= 14) {
- mImpl = new MediaSessionImplApi14(context, tag, mbrComponent, mbrIntent);
} else {
mImpl = new MediaSessionImplBase(context, tag, mbrComponent, mbrIntent);
}
@@ -895,6 +902,48 @@
public void onCustomAction(String action, Bundle extras) {
}
+ /**
+ * Called when a {@link MediaControllerCompat} wants to add a {@link QueueItem}
+ * with the given {@link MediaDescriptionCompat description} at the end of the play queue.
+ *
+ * @param description The {@link MediaDescriptionCompat} for creating the {@link QueueItem}
+ * to be inserted.
+ */
+ public void onAddQueueItem(MediaDescriptionCompat description) {
+ }
+
+ /**
+ * Called when a {@link MediaControllerCompat} wants to add a {@link QueueItem}
+ * with the given {@link MediaDescriptionCompat description} at the specified position
+ * in the play queue.
+ *
+ * @param description The {@link MediaDescriptionCompat} for creating the {@link QueueItem}
+ * to be inserted.
+ * @param index The index at which the created {@link QueueItem} is to be inserted.
+ */
+ public void onAddQueueItem(MediaDescriptionCompat description, int index) {
+ }
+
+ /**
+ * Called when a {@link MediaControllerCompat} wants to remove the first occurrence of the
+ * specified {@link QueueItem} with the given {@link MediaDescriptionCompat description}
+ * in the play queue.
+ *
+ * @param description The {@link MediaDescriptionCompat} for denoting the {@link QueueItem}
+ * to be removed.
+ */
+ public void onRemoveQueueItem(MediaDescriptionCompat description) {
+ }
+
+ /**
+ * Called when a {@link MediaControllerCompat} wants to remove a {@link QueueItem} at the
+ * specified position in the play queue.
+ *
+ * @param index The index of the element to be removed.
+ */
+ public void onRemoveQueueItemAt(int index) {
+ }
+
private class StubApi21 implements MediaSessionCompatApi21.Callback {
StubApi21() {
@@ -909,6 +958,25 @@
BundleCompat.putBinder(result, EXTRA_BINDER, impl.getExtraSessionBinder());
cb.send(0, result);
}
+ } else if (command.equals(MediaControllerCompat.COMMAND_ADD_QUEUE_ITEM)) {
+ extras.setClassLoader(MediaDescriptionCompat.class.getClassLoader());
+ Callback.this.onAddQueueItem(
+ (MediaDescriptionCompat) extras.getParcelable(
+ MediaControllerCompat.COMMAND_ARGUMENT_MEDIA_DESCRIPTION));
+ } else if (command.equals(MediaControllerCompat.COMMAND_ADD_QUEUE_ITEM_AT)) {
+ extras.setClassLoader(MediaDescriptionCompat.class.getClassLoader());
+ Callback.this.onAddQueueItem(
+ (MediaDescriptionCompat) extras.getParcelable(
+ MediaControllerCompat.COMMAND_ARGUMENT_MEDIA_DESCRIPTION),
+ extras.getInt(MediaControllerCompat.COMMAND_ARGUMENT_INDEX));
+ } else if (command.equals(MediaControllerCompat.COMMAND_REMOVE_QUEUE_ITEM)) {
+ extras.setClassLoader(MediaDescriptionCompat.class.getClassLoader());
+ Callback.this.onRemoveQueueItem(
+ (MediaDescriptionCompat) extras.getParcelable(
+ MediaControllerCompat.COMMAND_ARGUMENT_MEDIA_DESCRIPTION));
+ } else if (command.equals(MediaControllerCompat.COMMAND_REMOVE_QUEUE_ITEM_AT)) {
+ Callback.this.onRemoveQueueItemAt(
+ extras.getInt(MediaControllerCompat.COMMAND_ARGUMENT_INDEX));
} else {
Callback.this.onCommand(command, extras, cb);
}
@@ -1408,6 +1476,9 @@
}
static class MediaSessionImplBase implements MediaSessionImpl {
+ /***** RemoteControlClient States, we only need none as the others were public *******/
+ static final int RCC_PLAYSTATE_NONE = 0;
+
private final Context mContext;
private final ComponentName mMediaButtonReceiverComponentName;
private final PendingIntent mMediaButtonReceiverIntent;
@@ -1416,6 +1487,7 @@
final String mPackageName;
final String mTag;
final AudioManager mAudioManager;
+ final RemoteControlClient mRcc;
final Object mLock = new Object();
final RemoteCallbackList<IMediaControllerCallback> mControllerCallbacks
@@ -1425,6 +1497,7 @@
boolean mDestroyed = false;
boolean mIsActive = false;
private boolean mIsMbrRegistered = false;
+ private boolean mIsRccRegistered = false;
volatile Callback mCallback;
@SessionFlags int mFlags;
@@ -1475,6 +1548,7 @@
mRatingType = RatingCompat.RATING_NONE;
mVolumeType = MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
mLocalStream = AudioManager.STREAM_MUSIC;
+ mRcc = new RemoteControlClient(mbrIntent);
}
@Override
@@ -1494,10 +1568,22 @@
postToHandler(what, null);
}
+ void postToHandler(int what, int arg1) {
+ postToHandler(what, null, arg1);
+ }
+
void postToHandler(int what, Object obj) {
postToHandler(what, obj, null);
}
+ void postToHandler(int what, Object obj, int arg1) {
+ synchronized (mLock) {
+ if (mHandler != null) {
+ mHandler.post(what, obj, arg1);
+ }
+ }
+ }
+
void postToHandler(int what, Object obj, Bundle extras) {
synchronized (mLock) {
if (mHandler != null) {
@@ -1586,6 +1672,83 @@
mState = state;
}
sendState(state);
+ if (!mIsActive) {
+ // Don't set the state until after the RCC is registered
+ return;
+ }
+ if (state == null) {
+ mRcc.setPlaybackState(0);
+ mRcc.setTransportControlFlags(0);
+ } else {
+ // Set state
+ setRccState(state);
+
+ // Set transport control flags
+ mRcc.setTransportControlFlags(
+ getRccTransportControlFlagsFromActions(state.getActions()));
+ }
+ }
+
+ void setRccState(PlaybackStateCompat state) {
+ mRcc.setPlaybackState(getRccStateFromState(state.getState()));
+ }
+
+ int getRccStateFromState(int state) {
+ switch (state) {
+ case PlaybackStateCompat.STATE_CONNECTING:
+ case PlaybackStateCompat.STATE_BUFFERING:
+ return RemoteControlClient.PLAYSTATE_BUFFERING;
+ case PlaybackStateCompat.STATE_ERROR:
+ return RemoteControlClient.PLAYSTATE_ERROR;
+ case PlaybackStateCompat.STATE_FAST_FORWARDING:
+ return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
+ case PlaybackStateCompat.STATE_NONE:
+ return RCC_PLAYSTATE_NONE;
+ case PlaybackStateCompat.STATE_PAUSED:
+ return RemoteControlClient.PLAYSTATE_PAUSED;
+ case PlaybackStateCompat.STATE_PLAYING:
+ return RemoteControlClient.PLAYSTATE_PLAYING;
+ case PlaybackStateCompat.STATE_REWINDING:
+ return RemoteControlClient.PLAYSTATE_REWINDING;
+ case PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS:
+ return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
+ case PlaybackStateCompat.STATE_SKIPPING_TO_NEXT:
+ case PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM:
+ return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
+ case PlaybackStateCompat.STATE_STOPPED:
+ return RemoteControlClient.PLAYSTATE_STOPPED;
+ default:
+ return -1;
+ }
+ }
+
+ int getRccTransportControlFlagsFromActions(long actions) {
+ int transportControlFlags = 0;
+ if ((actions & PlaybackStateCompat.ACTION_STOP) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_STOP;
+ }
+ if ((actions & PlaybackStateCompat.ACTION_PAUSE) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
+ }
+ if ((actions & PlaybackStateCompat.ACTION_PLAY) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
+ }
+ if ((actions & PlaybackStateCompat.ACTION_REWIND) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
+ }
+ if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
+ }
+ if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
+ }
+ if ((actions & PlaybackStateCompat.ACTION_FAST_FORWARD) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
+ }
+ if ((actions & PlaybackStateCompat.ACTION_PLAY_PAUSE) != 0) {
+ transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
+ }
+ return transportControlFlags;
}
@Override
@@ -1600,6 +1763,81 @@
mMetadata = metadata;
}
sendMetadata(metadata);
+ if (!mIsActive) {
+ // Don't set metadata until after the rcc has been registered
+ return;
+ }
+ RemoteControlClient.MetadataEditor editor = buildRccMetadata(
+ metadata == null ? null : metadata.getBundle());
+ editor.apply();
+ }
+
+ RemoteControlClient.MetadataEditor buildRccMetadata(Bundle metadata) {
+ RemoteControlClient.MetadataEditor editor = mRcc.editMetadata(true);
+ if (metadata == null) {
+ return editor;
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ART)) {
+ Bitmap art = metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_ART);
+ editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
+ } else if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM_ART)) {
+ // Fall back to album art if the track art wasn't available
+ Bitmap art = metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART);
+ editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ARTIST)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_AUTHOR)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_AUTHOR,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_AUTHOR));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_COMPILATION)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_COMPILATION));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_COMPOSER)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPOSER,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_COMPOSER));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DATE)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_DATE,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_DATE));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER)) {
+ editor.putLong(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
+ metadata.getLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DURATION)) {
+ editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
+ metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_GENRE)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_GENRE,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_TITLE)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER)) {
+ editor.putLong(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+ metadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER));
+ }
+ if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_WRITER)) {
+ editor.putString(MediaMetadataRetriever.METADATA_KEY_WRITER,
+ metadata.getString(MediaMetadataCompat.METADATA_KEY_WRITER));
+ }
+ return editor;
}
@Override
@@ -1670,9 +1908,9 @@
// Registers/unregisters components as needed.
boolean update() {
+ boolean registeredRcc = false;
if (mIsActive) {
- // Register a MBR if it's supported, unregister it
- // if support was removed.
+ // Register a MBR if it's supported, unregister it if support was removed.
if (!mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) != 0) {
registerMediaButtonEventReceiver(mMediaButtonReceiverIntent,
mMediaButtonReceiverComponentName);
@@ -1682,6 +1920,20 @@
mMediaButtonReceiverComponentName);
mIsMbrRegistered = false;
}
+ // Register a RCC if it's supported, unregister it if support was removed.
+ if (!mIsRccRegistered && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
+ mAudioManager.registerRemoteControlClient(mRcc);
+ mIsRccRegistered = true;
+ registeredRcc = true;
+ } else if (mIsRccRegistered
+ && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) == 0) {
+ // RCC keeps the state while the system resets its state internally when
+ // we register RCC. Reset the state so that the states in RCC and the system
+ // are in sync when we re-register the RCC.
+ mRcc.setPlaybackState(0);
+ mAudioManager.unregisterRemoteControlClient(mRcc);
+ mIsRccRegistered = false;
+ }
} else {
// When inactive remove any registered components.
if (mIsMbrRegistered) {
@@ -1689,8 +1941,16 @@
mMediaButtonReceiverComponentName);
mIsMbrRegistered = false;
}
+ if (mIsRccRegistered) {
+ // RCC keeps the state while the system resets its state internally when
+ // we register RCC. Reset the state so that the states in RCC and the system
+ // are in sync when we re-register the RCC.
+ mRcc.setPlaybackState(0);
+ mAudioManager.unregisterRemoteControlClient(mRcc);
+ mIsRccRegistered = false;
+ }
}
- return false;
+ return registeredRcc;
}
void registerMediaButtonEventReceiver(PendingIntent mbrIntent, ComponentName mbrComponent) {
@@ -2097,6 +2357,26 @@
}
@Override
+ public void addQueueItem(MediaDescriptionCompat description) {
+ postToHandler(MessageHandler.MSG_ADD_QUEUE_ITEM, description);
+ }
+
+ @Override
+ public void addQueueItemAt(MediaDescriptionCompat description, int index) {
+ postToHandler(MessageHandler.MSG_ADD_QUEUE_ITEM_AT, description, index);
+ }
+
+ @Override
+ public void removeQueueItem(MediaDescriptionCompat description) {
+ postToHandler(MessageHandler.MSG_REMOVE_QUEUE_ITEM, description);
+ }
+
+ @Override
+ public void removeQueueItemAt(int index) {
+ postToHandler(MessageHandler.MSG_REMOVE_QUEUE_ITEM_AT, index);
+ }
+
+ @Override
public CharSequence getQueueTitle() {
return mQueueTitle;
}
@@ -2169,6 +2449,10 @@
private static final int MSG_SET_VOLUME = 22;
private static final int MSG_SET_REPEAT_MODE = 23;
private static final int MSG_SET_SHUFFLE_MODE_ENABLED = 24;
+ private static final int MSG_ADD_QUEUE_ITEM = 25;
+ private static final int MSG_ADD_QUEUE_ITEM_AT = 26;
+ private static final int MSG_REMOVE_QUEUE_ITEM = 27;
+ private static final int MSG_REMOVE_QUEUE_ITEM_AT = 28;
// KeyEvent constants only available on API 11+
private static final int KEYCODE_MEDIA_PAUSE = 127;
@@ -2270,14 +2554,26 @@
case MSG_CUSTOM_ACTION:
cb.onCustomAction((String) msg.obj, msg.getData());
break;
+ case MSG_ADD_QUEUE_ITEM:
+ cb.onAddQueueItem((MediaDescriptionCompat) msg.obj);
+ break;
+ case MSG_ADD_QUEUE_ITEM_AT:
+ cb.onAddQueueItem((MediaDescriptionCompat) msg.obj, msg.arg1);
+ break;
+ case MSG_REMOVE_QUEUE_ITEM:
+ cb.onRemoveQueueItem((MediaDescriptionCompat) msg.obj);
+ break;
+ case MSG_REMOVE_QUEUE_ITEM_AT:
+ cb.onRemoveQueueItemAt(msg.arg1);
+ break;
case MSG_ADJUST_VOLUME:
- adjustVolume((int) msg.obj, 0);
+ adjustVolume(msg.arg1, 0);
break;
case MSG_SET_VOLUME:
- setVolumeTo((int) msg.obj, 0);
+ setVolumeTo(msg.arg1, 0);
break;
case MSG_SET_REPEAT_MODE:
- cb.onSetRepeatMode((int) msg.obj);
+ cb.onSetRepeatMode(msg.arg1);
break;
case MSG_SET_SHUFFLE_MODE_ENABLED:
cb.onSetShuffleModeEnabled((boolean) msg.obj);
@@ -2347,219 +2643,8 @@
}
}
- @RequiresApi(14)
- static class MediaSessionImplApi14 extends MediaSessionImplBase {
- /***** RemoteControlClient States, we only need none as the others were public *******/
- static final int RCC_PLAYSTATE_NONE = 0;
-
- final RemoteControlClient mRcc;
-
- private boolean mIsRccRegistered = false;
-
- MediaSessionImplApi14(Context context, String tag, ComponentName mbrComponent,
- PendingIntent mbrIntent) {
- super(context, tag, mbrComponent, mbrIntent);
- mRcc = new RemoteControlClient(mbrIntent);
- }
-
- @Override
- public void setPlaybackState(PlaybackStateCompat state) {
- super.setPlaybackState(state);
- if (!mIsActive) {
- // Don't set the state until after the RCC is registered
- return;
- }
- if (state == null) {
- mRcc.setPlaybackState(0);
- mRcc.setTransportControlFlags(0);
- } else {
- // Set state
- setRccState(state);
-
- // Set transport control flags
- mRcc.setTransportControlFlags(
- getRccTransportControlFlagsFromActions(state.getActions()));
- }
- }
-
- void setRccState(PlaybackStateCompat state) {
- mRcc.setPlaybackState(getRccStateFromState(state.getState()));
- }
-
- int getRccStateFromState(int state) {
- switch (state) {
- case PlaybackStateCompat.STATE_CONNECTING:
- case PlaybackStateCompat.STATE_BUFFERING:
- return RemoteControlClient.PLAYSTATE_BUFFERING;
- case PlaybackStateCompat.STATE_ERROR:
- return RemoteControlClient.PLAYSTATE_ERROR;
- case PlaybackStateCompat.STATE_FAST_FORWARDING:
- return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
- case PlaybackStateCompat.STATE_NONE:
- return RCC_PLAYSTATE_NONE;
- case PlaybackStateCompat.STATE_PAUSED:
- return RemoteControlClient.PLAYSTATE_PAUSED;
- case PlaybackStateCompat.STATE_PLAYING:
- return RemoteControlClient.PLAYSTATE_PLAYING;
- case PlaybackStateCompat.STATE_REWINDING:
- return RemoteControlClient.PLAYSTATE_REWINDING;
- case PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS:
- return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
- case PlaybackStateCompat.STATE_SKIPPING_TO_NEXT:
- case PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM:
- return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
- case PlaybackStateCompat.STATE_STOPPED:
- return RemoteControlClient.PLAYSTATE_STOPPED;
- default:
- return -1;
- }
- }
-
- int getRccTransportControlFlagsFromActions(long actions) {
- int transportControlFlags = 0;
- if ((actions & PlaybackStateCompat.ACTION_STOP) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_STOP;
- }
- if ((actions & PlaybackStateCompat.ACTION_PAUSE) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
- }
- if ((actions & PlaybackStateCompat.ACTION_PLAY) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
- }
- if ((actions & PlaybackStateCompat.ACTION_REWIND) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
- }
- if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
- }
- if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
- }
- if ((actions & PlaybackStateCompat.ACTION_FAST_FORWARD) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
- }
- if ((actions & PlaybackStateCompat.ACTION_PLAY_PAUSE) != 0) {
- transportControlFlags |= RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
- }
- return transportControlFlags;
- }
-
- @Override
- public void setMetadata(MediaMetadataCompat metadata) {
- super.setMetadata(metadata);
- if (!mIsActive) {
- // Don't set metadata until after the rcc has been registered
- return;
- }
- RemoteControlClient.MetadataEditor editor = buildRccMetadata(
- metadata == null ? null : metadata.getBundle());
- editor.apply();
- }
-
- RemoteControlClient.MetadataEditor buildRccMetadata(Bundle metadata) {
- RemoteControlClient.MetadataEditor editor = mRcc.editMetadata(true);
- if (metadata == null) {
- return editor;
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ART)) {
- Bitmap art = metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_ART);
- editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
- } else if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM_ART)) {
- // Fall back to album art if the track art wasn't available
- Bitmap art = metadata.getParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART);
- editor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, art);
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ARTIST)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_AUTHOR)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_AUTHOR,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_AUTHOR));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_COMPILATION)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_COMPILATION));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_COMPOSER)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_COMPOSER,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_COMPOSER));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DATE)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_DATE,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_DATE));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER)) {
- editor.putLong(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
- metadata.getLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_DURATION)) {
- editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
- metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_GENRE)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_GENRE,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_TITLE)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER)) {
- editor.putLong(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
- metadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER));
- }
- if (metadata.containsKey(MediaMetadataCompat.METADATA_KEY_WRITER)) {
- editor.putString(MediaMetadataRetriever.METADATA_KEY_WRITER,
- metadata.getString(MediaMetadataCompat.METADATA_KEY_WRITER));
- }
- return editor;
- }
-
- @Override
- boolean update() {
- super.update();
- boolean registeredRcc = false;
- if (mIsActive) {
- // Register a RCC if it's supported, unregister it if not.
- if (!mIsRccRegistered && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
- mAudioManager.registerRemoteControlClient(mRcc);
- mIsRccRegistered = true;
- registeredRcc = true;
- } else if (mIsRccRegistered
- && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) == 0) {
- // RCC keeps the state while the system resets its state internally when
- // we register RCC. Reset the state so that the states in RCC and the system
- // are in sync when we re-register the RCC.
- mRcc.setPlaybackState(0);
- mAudioManager.unregisterRemoteControlClient(mRcc);
- mIsRccRegistered = false;
- }
- } else {
- // When inactive remove any registered components.
- if (mIsRccRegistered) {
- // RCC keeps the state while the system resets its state internally when
- // we register RCC. Reset the state so that the states in RCC and the system
- // are in sync when we re-register the RCC.
- mRcc.setPlaybackState(0);
- mAudioManager.unregisterRemoteControlClient(mRcc);
- mIsRccRegistered = false;
- }
- }
- return registeredRcc;
- }
- }
-
@RequiresApi(18)
- static class MediaSessionImplApi18 extends MediaSessionImplApi14 {
+ static class MediaSessionImplApi18 extends MediaSessionImplBase {
private static boolean sIsMbrPendingIntentSupported = true;
MediaSessionImplApi18(Context context, String tag, ComponentName mbrComponent,
@@ -3131,6 +3216,30 @@
}
@Override
+ public void addQueueItem(MediaDescriptionCompat descriptionCompat) {
+ // Will not be called.
+ throw new AssertionError();
+ }
+
+ @Override
+ public void addQueueItemAt(MediaDescriptionCompat descriptionCompat, int index) {
+ // Will not be called.
+ throw new AssertionError();
+ }
+
+ @Override
+ public void removeQueueItem(MediaDescriptionCompat description) {
+ // Will not be called.
+ throw new AssertionError();
+ }
+
+ @Override
+ public void removeQueueItemAt(int index) {
+ // Will not be called.
+ throw new AssertionError();
+ }
+
+ @Override
public CharSequence getQueueTitle() {
// Will not be called.
throw new AssertionError();
diff --git a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java b/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
index bf176ac..2598bef 100644
--- a/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
+++ b/media-compat/tests/src/android/support/v4/media/session/MediaControllerCompatTest.java
@@ -31,6 +31,7 @@
import android.os.ResultReceiver;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.PollingCheck;
import android.support.v4.media.RatingCompat;
import android.support.v4.media.VolumeProviderCompat;
@@ -65,6 +66,7 @@
public void run() {
mSession = new MediaSessionCompat(getContext(), SESSION_TAG);
mSession.setCallback(mCallback, mHandler);
+ mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
mController = mSession.getController();
}
});
@@ -123,7 +125,47 @@
}
}
- // TODO(hdmoon): Uncomment after fixing this test. This test causes an Exception on System UI.
+ @Test
+ @SmallTest
+ public void testAddRemoveQueueItems() throws Exception {
+ final String mediaId = "media_id";
+ final String mediaTitle = "media_title";
+ MediaDescriptionCompat itemDescription = new MediaDescriptionCompat.Builder()
+ .setMediaId(mediaId).setTitle(mediaTitle).build();
+
+ synchronized (mWaitLock) {
+ mCallback.reset();
+ mController.addQueueItem(itemDescription);
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(mCallback.mOnAddQueueItemCalled);
+ assertEquals(-1, mCallback.mQueueIndex);
+ assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
+ assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
+
+ mCallback.reset();
+ mController.addQueueItem(itemDescription, 0);
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(mCallback.mOnAddQueueItemAtCalled);
+ assertEquals(0, mCallback.mQueueIndex);
+ assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
+ assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
+
+ mCallback.reset();
+ mController.removeQueueItemAt(0);
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(mCallback.mOnRemoveQueueItemAtCalled);
+ assertEquals(0, mCallback.mQueueIndex);
+
+ mCallback.reset();
+ mController.removeQueueItem(itemDescription);
+ mWaitLock.wait(TIME_OUT_MS);
+ assertTrue(mCallback.mOnRemoveQueueItemCalled);
+ assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
+ assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
+ }
+ }
+
+ // TODO: Uncomment after fixing this test. This test causes an Exception on System UI.
// @Test
// @SmallTest
public void testVolumeControl() throws Exception {
@@ -354,6 +396,8 @@
private ResultReceiver mCommandCallback;
private int mRepeatMode;
private boolean mShuffleModeEnabled;
+ private int mQueueIndex;
+ private MediaDescriptionCompat mQueueDescription;
private boolean mOnPlayCalled;
private boolean mOnPauseCalled;
@@ -376,6 +420,10 @@
private boolean mOnPrepareFromUriCalled;
private boolean mOnSetRepeatModeCalled;
private boolean mOnSetShuffleModeEnabledCalled;
+ private boolean mOnAddQueueItemCalled;
+ private boolean mOnAddQueueItemAtCalled;
+ private boolean mOnRemoveQueueItemCalled;
+ private boolean mOnRemoveQueueItemAtCalled;
public void reset() {
mSeekPosition = -1;
@@ -390,6 +438,8 @@
mCommandCallback = null;
mShuffleModeEnabled = false;
mRepeatMode = PlaybackStateCompat.REPEAT_MODE_NONE;
+ mQueueIndex = -1;
+ mQueueDescription = null;
mOnPlayCalled = false;
mOnPauseCalled = false;
@@ -412,6 +462,10 @@
mOnPrepareFromUriCalled = false;
mOnSetRepeatModeCalled = false;
mOnSetShuffleModeEnabledCalled = false;
+ mOnAddQueueItemCalled = false;
+ mOnAddQueueItemAtCalled = false;
+ mOnRemoveQueueItemCalled = false;
+ mOnRemoveQueueItemAtCalled = false;
}
@Override
@@ -596,6 +650,34 @@
}
@Override
+ public void onAddQueueItem(MediaDescriptionCompat description) {
+ synchronized (mWaitLock) {
+ mOnAddQueueItemCalled = true;
+ mQueueDescription = description;
+ mWaitLock.notify();
+ }
+ }
+
+ @Override
+ public void onAddQueueItem(MediaDescriptionCompat description, int index) {
+ synchronized (mWaitLock) {
+ mOnAddQueueItemAtCalled = true;
+ mQueueIndex = index;
+ mQueueDescription = description;
+ mWaitLock.notify();
+ }
+ }
+
+ @Override
+ public void onRemoveQueueItem(MediaDescriptionCompat description) {
+ synchronized (mWaitLock) {
+ mOnRemoveQueueItemCalled = true;
+ mQueueDescription = description;
+ mWaitLock.notify();
+ }
+ }
+
+ @Override
public void onSetShuffleModeEnabled(boolean enabled) {
synchronized (mWaitLock) {
mOnSetShuffleModeEnabledCalled = true;
@@ -603,5 +685,14 @@
mWaitLock.notify();
}
}
+
+ @Override
+ public void onRemoveQueueItemAt(int index) {
+ synchronized (mWaitLock) {
+ mOnRemoveQueueItemAtCalled = true;
+ mQueueIndex = index;
+ mWaitLock.notify();
+ }
+ }
}
}
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index a584abc..e941c1d 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -68,6 +68,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
+import android.widget.EdgeEffect;
import android.widget.OverScroller;
import java.lang.annotation.Retention;
@@ -403,7 +404,7 @@
*/
private int mDispatchScrollCounter = 0;
- private EdgeEffectCompat mLeftGlow, mTopGlow, mRightGlow, mBottomGlow;
+ private EdgeEffect mLeftGlow, mTopGlow, mRightGlow, mBottomGlow;
ItemAnimator mItemAnimator = new DefaultItemAnimator();
@@ -2105,26 +2106,22 @@
boolean invalidate = false;
if (overscrollX < 0) {
ensureLeftGlow();
- if (mLeftGlow.onPull(-overscrollX / getWidth(), 1f - y / getHeight())) {
- invalidate = true;
- }
+ EdgeEffectCompat.onPull(mLeftGlow, -overscrollX / getWidth(), 1f - y / getHeight());
+ invalidate = true;
} else if (overscrollX > 0) {
ensureRightGlow();
- if (mRightGlow.onPull(overscrollX / getWidth(), y / getHeight())) {
- invalidate = true;
- }
+ EdgeEffectCompat.onPull(mRightGlow, overscrollX / getWidth(), y / getHeight());
+ invalidate = true;
}
if (overscrollY < 0) {
ensureTopGlow();
- if (mTopGlow.onPull(-overscrollY / getHeight(), x / getWidth())) {
- invalidate = true;
- }
+ EdgeEffectCompat.onPull(mTopGlow, -overscrollY / getHeight(), x / getWidth());
+ invalidate = true;
} else if (overscrollY > 0) {
ensureBottomGlow();
- if (mBottomGlow.onPull(overscrollY / getHeight(), 1f - x / getWidth())) {
- invalidate = true;
- }
+ EdgeEffectCompat.onPull(mBottomGlow, overscrollY / getHeight(), 1f - x / getWidth());
+ invalidate = true;
}
if (invalidate || overscrollX != 0 || overscrollY != 0) {
@@ -2134,10 +2131,22 @@
private void releaseGlows() {
boolean needsInvalidate = false;
- if (mLeftGlow != null) needsInvalidate = mLeftGlow.onRelease();
- if (mTopGlow != null) needsInvalidate |= mTopGlow.onRelease();
- if (mRightGlow != null) needsInvalidate |= mRightGlow.onRelease();
- if (mBottomGlow != null) needsInvalidate |= mBottomGlow.onRelease();
+ if (mLeftGlow != null) {
+ mLeftGlow.onRelease();
+ needsInvalidate = mLeftGlow.isFinished();
+ }
+ if (mTopGlow != null) {
+ mTopGlow.onRelease();
+ needsInvalidate |= mTopGlow.isFinished();
+ }
+ if (mRightGlow != null) {
+ mRightGlow.onRelease();
+ needsInvalidate |= mRightGlow.isFinished();
+ }
+ if (mBottomGlow != null) {
+ mBottomGlow.onRelease();
+ needsInvalidate |= mBottomGlow.isFinished();
+ }
if (needsInvalidate) {
ViewCompat.postInvalidateOnAnimation(this);
}
@@ -2146,16 +2155,20 @@
void considerReleasingGlowsOnScroll(int dx, int dy) {
boolean needsInvalidate = false;
if (mLeftGlow != null && !mLeftGlow.isFinished() && dx > 0) {
- needsInvalidate = mLeftGlow.onRelease();
+ mLeftGlow.onRelease();
+ needsInvalidate = mLeftGlow.isFinished();
}
if (mRightGlow != null && !mRightGlow.isFinished() && dx < 0) {
- needsInvalidate |= mRightGlow.onRelease();
+ mRightGlow.onRelease();
+ needsInvalidate |= mRightGlow.isFinished();
}
if (mTopGlow != null && !mTopGlow.isFinished() && dy > 0) {
- needsInvalidate |= mTopGlow.onRelease();
+ mTopGlow.onRelease();
+ needsInvalidate |= mTopGlow.isFinished();
}
if (mBottomGlow != null && !mBottomGlow.isFinished() && dy < 0) {
- needsInvalidate |= mBottomGlow.onRelease();
+ mBottomGlow.onRelease();
+ needsInvalidate |= mBottomGlow.isFinished();
}
if (needsInvalidate) {
ViewCompat.postInvalidateOnAnimation(this);
@@ -2188,7 +2201,7 @@
if (mLeftGlow != null) {
return;
}
- mLeftGlow = new EdgeEffectCompat(getContext());
+ mLeftGlow = new EdgeEffect(getContext());
if (mClipToPadding) {
mLeftGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2201,7 +2214,7 @@
if (mRightGlow != null) {
return;
}
- mRightGlow = new EdgeEffectCompat(getContext());
+ mRightGlow = new EdgeEffect(getContext());
if (mClipToPadding) {
mRightGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2214,7 +2227,7 @@
if (mTopGlow != null) {
return;
}
- mTopGlow = new EdgeEffectCompat(getContext());
+ mTopGlow = new EdgeEffect(getContext());
if (mClipToPadding) {
mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
@@ -2228,7 +2241,7 @@
if (mBottomGlow != null) {
return;
}
- mBottomGlow = new EdgeEffectCompat(getContext());
+ mBottomGlow = new EdgeEffect(getContext());
if (mClipToPadding) {
mBottomGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingTop() - getPaddingBottom());