Merge "Clarify dangers of LLM#getExtraLayoutSpace" into nyc-support-25.1-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4caef90..2811ea9 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,5 @@
[Hook Scripts]
-checkstyle_hook = ../../development/tools/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
[Builtin Hooks]
commit_msg_changeid_field = true
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 78b0c50..d835985 100644
--- a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -2302,7 +2302,9 @@
public void setCallback(Callback callback, Handler handler) {
MediaSessionCompatApi21.setCallback(mSessionObj,
callback == null ? null : callback.mCallbackObj, handler);
- callback.mSessionImpl = new WeakReference<MediaSessionImpl>(this);
+ if (callback != null) {
+ callback.mSessionImpl = new WeakReference<MediaSessionImpl>(this);
+ }
}
@Override
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java
index ca6ee77..7d2904a 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java
@@ -151,6 +151,9 @@
* @param actions The list of actions to be managed.
*/
public void setActions(List<GuidedAction> actions) {
+ if (!mIsSubAdapter) {
+ mStylist.collapseAction(false);
+ }
mActionOnFocusListener.unFocus();
mActions.clear();
mActions.addAll(actions);
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
index 192b20e..50aaa62 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
@@ -29,6 +29,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.support.v17.leanback.testutils.PollingCheck;
import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -354,4 +355,58 @@
PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
verify(first, timeout(ON_DESTROY_TIMEOUT).times(1)).onDestroy();
}
+
+ @Test
+ public void setActionsWhenSubActionsExpanded() throws Throwable {
+ final String firstFragmentName = generateMethodTestName("first");
+ GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName);
+ doAnswer(new Answer<Void>() {
+ public Void answer(InvocationOnMock invocation) {
+ List actions = (List) invocation.getArguments()[0];
+ List<GuidedAction> subActions = new ArrayList<GuidedAction>();
+ subActions.add(new GuidedAction.Builder().id(2000).title("item1").build());
+ actions.add(new GuidedAction.Builder().id(1000).subActions(subActions)
+ .title("list").build());
+ return null;
+ }
+ }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+ doAnswer(new Answer<Boolean>() {
+ public Boolean answer(InvocationOnMock invocation) {
+ GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
+ invocation.getMock();
+ GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+ if (action.getId() == 2000) {
+ List<GuidedAction> newActions = new ArrayList<GuidedAction>();
+ newActions.add(new GuidedAction.Builder().id(1001).title("item2").build());
+ obj.getFragment().setActions(newActions);
+ return false;
+ }
+ return false;
+ }
+ }).when(first).onSubGuidedActionClicked(any(GuidedAction.class));
+
+ final GuidedStepFragmentTestActivity activity = launchTestActivity(firstFragmentName);
+
+ // after clicked, it sub actions list should expand
+ View firstView = first.getFragment().getActionItemView(0);
+ assertTrue(firstView.hasFocus());
+ sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+ PollingCheck.waitFor(new ExpandTransitionFinish(first));
+ assertFalse(firstView.hasFocus());
+
+ sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+ ArgumentCaptor<GuidedAction> actionCapture = ArgumentCaptor.forClass(GuidedAction.class);
+ verify(first, times(1)).onSubGuidedActionClicked(actionCapture.capture());
+ // after clicked a sub action, whole action list is replaced.
+ PollingCheck.waitFor(new ExpandTransitionFinish(first));
+ assertFalse(first.getFragment().isExpanded());
+ View newFirstView = first.getFragment().getActionItemView(0);
+ assertTrue(newFirstView.hasFocus());
+ assertTrue(newFirstView.getVisibility() == View.VISIBLE);
+ GuidedActionsStylist.ViewHolder vh = (GuidedActionsStylist.ViewHolder) first.getFragment()
+ .getGuidedActionsStylist().getActionsGridView().getChildViewHolder(newFirstView);
+ assertEquals(1001, vh.getAction().getId());
+
+ }
+
}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
index 879292f..7d6b54f 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
@@ -32,6 +32,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.support.v17.leanback.testutils.PollingCheck;
import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -357,4 +358,58 @@
PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
verify(first, timeout(ON_DESTROY_TIMEOUT).times(1)).onDestroy();
}
+
+ @Test
+ public void setActionsWhenSubActionsExpanded() throws Throwable {
+ final String firstFragmentName = generateMethodTestName("first");
+ GuidedStepTestSupportFragment.Provider first = mockProvider(firstFragmentName);
+ doAnswer(new Answer<Void>() {
+ public Void answer(InvocationOnMock invocation) {
+ List actions = (List) invocation.getArguments()[0];
+ List<GuidedAction> subActions = new ArrayList<GuidedAction>();
+ subActions.add(new GuidedAction.Builder().id(2000).title("item1").build());
+ actions.add(new GuidedAction.Builder().id(1000).subActions(subActions)
+ .title("list").build());
+ return null;
+ }
+ }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+ doAnswer(new Answer<Boolean>() {
+ public Boolean answer(InvocationOnMock invocation) {
+ GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
+ invocation.getMock();
+ GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+ if (action.getId() == 2000) {
+ List<GuidedAction> newActions = new ArrayList<GuidedAction>();
+ newActions.add(new GuidedAction.Builder().id(1001).title("item2").build());
+ obj.getFragment().setActions(newActions);
+ return false;
+ }
+ return false;
+ }
+ }).when(first).onSubGuidedActionClicked(any(GuidedAction.class));
+
+ final GuidedStepSupportFragmentTestActivity activity = launchTestActivity(firstFragmentName);
+
+ // after clicked, it sub actions list should expand
+ View firstView = first.getFragment().getActionItemView(0);
+ assertTrue(firstView.hasFocus());
+ sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+ PollingCheck.waitFor(new ExpandTransitionFinish(first));
+ assertFalse(firstView.hasFocus());
+
+ sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+ ArgumentCaptor<GuidedAction> actionCapture = ArgumentCaptor.forClass(GuidedAction.class);
+ verify(first, times(1)).onSubGuidedActionClicked(actionCapture.capture());
+ // after clicked a sub action, whole action list is replaced.
+ PollingCheck.waitFor(new ExpandTransitionFinish(first));
+ assertFalse(first.getFragment().isExpanded());
+ View newFirstView = first.getFragment().getActionItemView(0);
+ assertTrue(newFirstView.hasFocus());
+ assertTrue(newFirstView.getVisibility() == View.VISIBLE);
+ GuidedActionsStylist.ViewHolder vh = (GuidedActionsStylist.ViewHolder) first.getFragment()
+ .getGuidedActionsStylist().getActionsGridView().getChildViewHolder(newFirstView);
+ assertEquals(1001, vh.getAction().getId());
+
+ }
+
}
diff --git a/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java b/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
index 85071a4..7ade21d 100644
--- a/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
+++ b/v7/mediarouter/jellybean/android/support/v7/media/MediaRouterJellybean.java
@@ -121,9 +121,9 @@
Field globalRouterField = routerObj.getClass().getDeclaredField("sStatic");
globalRouterField.setAccessible(true);
Object globalRouterObj = globalRouterField.get(null);
- Method method = globalRouterObj.getClass().getDeclaredMethod("isBluetoothA2dpOn", null);
+ Method method = globalRouterObj.getClass().getDeclaredMethod("isBluetoothA2dpOn");
method.setAccessible(true);
- Object result = method.invoke(globalRouterObj, null);
+ Object result = method.invoke(globalRouterObj);
return (Boolean) result;
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException
| NoSuchMethodException | InvocationTargetException e) {
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
index adbe4dd..19f31f8 100644
--- a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -2097,15 +2097,23 @@
if (mPrefetchDistances == null || mPrefetchDistances.length < mSpanCount) {
mPrefetchDistances = new int[mSpanCount];
}
+
+ int itemPrefetchCount = 0;
for (int i = 0; i < mSpanCount; i++) {
- mPrefetchDistances[i] = mLayoutState.mItemDirection == LAYOUT_START
+ // compute number of pixels past the edge of the viewport that the current span extends
+ int distance = mLayoutState.mItemDirection == LAYOUT_START
? mLayoutState.mStartLine - mSpans[i].getStartLine(mLayoutState.mStartLine)
: mSpans[i].getEndLine(mLayoutState.mEndLine) - mLayoutState.mEndLine;
+ if (distance >= 0) {
+ // span extends to the edge, so prefetch next item
+ mPrefetchDistances[itemPrefetchCount] = distance;
+ itemPrefetchCount++;
+ }
}
- Arrays.sort(mPrefetchDistances, 0, mSpanCount);
+ Arrays.sort(mPrefetchDistances, 0, itemPrefetchCount);
// then assign them in order to the next N views (where N = span count)
- for (int i = 0; i < mSpanCount && mLayoutState.hasMore(state); i++) {
+ for (int i = 0; i < itemPrefetchCount && mLayoutState.hasMore(state); i++) {
layoutPrefetchRegistry.addPosition(mLayoutState.mCurrentPosition, mPrefetchDistances[i]);
mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
index cc39a87..7ab616f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
@@ -515,6 +515,50 @@
}
@Test
+ public void prefetchStaggeredPastBoundary() {
+ StaggeredGridLayoutManager sglm =
+ new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
+ mRecyclerView.setLayoutManager(sglm);
+ mRecyclerView.setAdapter(new RecyclerView.Adapter() {
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new RecyclerView.ViewHolder(new View(getContext())) {};
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ holder.itemView.setMinimumWidth(100);
+ holder.itemView.setMinimumHeight(position == 0 ? 100 : 200);
+ }
+
+ @Override
+ public int getItemCount() {
+ return 2;
+ }
+ });
+
+ layout(200, 100);
+ mRecyclerView.scrollBy(0, 50);
+
+ /* Each row is 50 pixels:
+ * ------------- *
+ *___0___|___1___*
+ * 0 | 1 *
+ *_______|___1___*
+ * | 1 *
+ */
+ assertEquals(2, mRecyclerView.getChildCount());
+ assertEquals(0, sglm.getFirstChildPosition());
+ assertEquals(1, sglm.getLastChildPosition());
+
+ // prefetch upward gets nothing
+ CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, -10);
+
+ // prefetch downward gets nothing (and doesn't crash...)
+ CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, 10);
+ }
+
+ @Test
public void prefetchItemsSkipAnimations() {
LinearLayoutManager llm = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(llm);