Merge "Sharesheet - Fix 4->8 direct share expansion glitch"

This commit is contained in:
TreeHugger Robot
2019-03-27 18:04:58 +00:00
committed by Android (Google) Code Review
7 changed files with 116 additions and 90 deletions

View File

@@ -163,6 +163,8 @@ public class ChooserActivity extends ResolverActivity {
*/
private static final int NO_DIRECT_SHARE_ANIM_IN_MILLIS = 200;
private static final float DIRECT_SHARE_EXPANSION_RATE = 0.7f;
// TODO(b/121287224): Re-evaluate this limit
private static final int SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
@@ -435,9 +437,13 @@ public class ChooserActivity extends ResolverActivity {
mChooserRowServiceSpacing = getResources()
.getDimensionPixelSize(R.dimen.chooser_service_spacing);
// expand/shrink direct share 4 -> 8 viewgroup
if (mResolverDrawerLayout != null && isSendAction(target)) {
mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
if (mResolverDrawerLayout != null) {
mResolverDrawerLayout.addOnLayoutChangeListener(this::handleLayoutChange);
// expand/shrink direct share 4 -> 8 viewgroup
if (isSendAction(target)) {
mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
}
}
if (DEBUG) {
@@ -878,18 +884,9 @@ public class ChooserActivity extends ResolverActivity {
mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets));
}
mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
if (listView != null) {
listView.setItemsCanFocus(true);
listView.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
if (mChooserRowAdapter.calculateMaxTargetsPerRow(right - left)) {
adapterView.setAdapter(mChooserRowAdapter);
}
});
}
adapterView.setAdapter(mChooserRowAdapter);
}
@Override
@@ -1728,6 +1725,66 @@ public class ChooserActivity extends ResolverActivity {
}
}
/*
* Need to dynamically adjust how many icons can fit per row before we add them,
* which also means setting the correct offset to initially show the content
* preview area + 2 rows of targets
*/
private void handleLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
if (mChooserRowAdapter == null || mAdapterView == null) {
return;
}
if (mChooserRowAdapter.calculateMaxTargetsPerRow(right - left)
|| mAdapterView.getAdapter() == null) {
mAdapterView.setAdapter(mChooserRowAdapter);
getMainThreadHandler().post(() -> {
if (mResolverDrawerLayout == null || mChooserRowAdapter == null) {
return;
}
int offset = 0;
int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
+ mChooserRowAdapter.getServiceTargetRowCount()
+ mChooserRowAdapter.getCallerTargetRowCount();
// then this is most likely not a SEND_* action, so check
// the app target count
if (rowsToShow == 0) {
rowsToShow = mChooserRowAdapter.getCount();
}
// still zero? then use a default height and leave, which
// can happen when there are no targets to show
if (rowsToShow == 0) {
offset = getResources().getDimensionPixelSize(
R.dimen.chooser_max_collapsed_height);
mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
return;
}
int lastHeight = 0;
rowsToShow = Math.max(3, rowsToShow);
for (int i = 0; i < Math.min(rowsToShow, mAdapterView.getChildCount()); i++) {
lastHeight = mAdapterView.getChildAt(i).getHeight();
offset += lastHeight;
}
if (lastHeight != 0 && isSendAction(getTargetIntent())) {
// make sure to leave room for direct share 4->8 expansion
int expansionArea =
(int) (mResolverDrawerLayout.getUncollapsibleHeight()
/ DIRECT_SHARE_EXPANSION_RATE);
offset = Math.min(offset, bottom - top - lastHeight - expansionArea);
}
mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
});
}
}
public class ChooserListAdapter extends ResolveListAdapter {
public static final int TARGET_BAD = -1;
public static final int TARGET_CALLER = 0;
@@ -2541,7 +2598,6 @@ public class ChooserActivity extends ResolverActivity {
getRow(0).measure(spec, spec);
getRow(1).measure(spec, spec);
// uses ChooserActiivty state variables to track height
mDirectShareMinHeight = getRow(0).getMeasuredHeight();
mDirectShareCurrHeight = mDirectShareCurrHeight > 0
? mDirectShareCurrHeight : mDirectShareMinHeight;
@@ -2574,18 +2630,18 @@ public class ChooserActivity extends ResolverActivity {
}
public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) {
// only expand if we have more than 4 targets, and delay that decision until
// they start to scroll
if (mHideDirectShareExpansion) {
return;
}
// only expand if we have more than maxTargetsPerRow, and delay that decision
// until they start to scroll
if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
mHideDirectShareExpansion = true;
return;
}
int yDiff = (int) ((oldy - y) * 0.7f);
int yDiff = (int) ((oldy - y) * DIRECT_SHARE_EXPANSION_RATE);
int prevHeight = mDirectShareCurrHeight;
mDirectShareCurrHeight = Math.min(mDirectShareCurrHeight + yDiff,
@@ -2593,27 +2649,31 @@ public class ChooserActivity extends ResolverActivity {
mDirectShareCurrHeight = Math.max(mDirectShareCurrHeight, mDirectShareMinHeight);
yDiff = mDirectShareCurrHeight - prevHeight;
if (view == null || view.getChildCount() == 0) {
if (view == null || view.getChildCount() == 0 || yDiff == 0) {
return;
}
int index = mChooserRowAdapter.getContentPreviewRowCount();
// locate the item to expand, and offset the rows below that one
boolean foundExpansion = false;
for (int i = 0; i < view.getChildCount(); i++) {
View child = view.getChildAt(i);
ViewGroup expansionGroup = (ViewGroup) view.getChildAt(index);
int widthSpec = MeasureSpec.makeMeasureSpec(expansionGroup.getWidth(),
MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(mDirectShareCurrHeight,
MeasureSpec.EXACTLY);
expansionGroup.measure(widthSpec, heightSpec);
expansionGroup.getLayoutParams().height = expansionGroup.getMeasuredHeight();
expansionGroup.layout(expansionGroup.getLeft(), expansionGroup.getTop(),
expansionGroup.getRight(),
expansionGroup.getTop() + expansionGroup.getMeasuredHeight());
if (foundExpansion) {
child.offsetTopAndBottom(yDiff);
} else {
if (child.getTag() != null && child.getTag() instanceof DirectShareViewHolder) {
int widthSpec = MeasureSpec.makeMeasureSpec(child.getWidth(),
MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(mDirectShareCurrHeight,
MeasureSpec.EXACTLY);
child.measure(widthSpec, heightSpec);
child.getLayoutParams().height = child.getMeasuredHeight();
child.layout(child.getLeft(), child.getTop(), child.getRight(),
child.getTop() + child.getMeasuredHeight());
// reposition list items
int items = view.getChildCount();
for (int i = index + 1; i < items; i++) {
view.getChildAt(i).offsetTopAndBottom(yDiff);
foundExpansion = true;
}
}
}
}
}
@@ -2771,47 +2831,6 @@ public class ChooserActivity extends ResolverActivity {
}
}
class OffsetDataSetObserver extends DataSetObserver {
private final AbsListView mListView;
private int mCachedViewType = -1;
private View mCachedView;
public OffsetDataSetObserver(AbsListView listView) {
mListView = listView;
}
@Override
public void onChanged() {
if (mResolverDrawerLayout == null) {
return;
}
final int chooserTargetRows = mChooserRowAdapter.getServiceTargetRowCount();
int offset = 0;
for (int i = 0; i < chooserTargetRows; i++) {
final int pos = mChooserRowAdapter.getContentPreviewRowCount() + i;
final int vt = mChooserRowAdapter.getItemViewType(pos);
if (vt != mCachedViewType) {
mCachedView = null;
}
final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
int height = ((RowViewHolder) (v.getTag())).getMeasuredRowHeight();
offset += (int) (height);
if (vt >= 0) {
mCachedViewType = vt;
mCachedView = v;
} else {
mCachedViewType = -1;
}
}
mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
}
}
/**
* Used internally to round image corners while obeying view padding.
*/

View File

@@ -868,6 +868,13 @@ public class ResolverDrawerLayout extends ViewGroup {
setMeasuredDimension(sourceWidth, heightSize);
}
/**
* @return The space reserved by views with 'alwaysShow=true'
*/
public int getUncollapsibleHeight() {
return mUncollapsibleHeight;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = getWidth();

View File

@@ -13,11 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M20.0,9.0L4.0,9.0l0.0,2.0l16.0,0.0L20.0,9.0zM4.0,15.0l16.0,0.0l0.0,-2.0L4.0,13.0l0.0,2.0z"/>
</vector>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#FFFFFFFF" />
<corners android:radius="2dp" />
</shape>

View File

@@ -20,7 +20,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxCollapsedHeight="288dp"
android:maxCollapsedHeight="0dp"
android:maxCollapsedHeightSmall="56dp"
android:id="@id/contentPanel">
@@ -32,12 +32,12 @@
<ImageView
android:id="@+id/drag"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:layout_width="32dp"
android:layout_height="4dp"
android:src="@drawable/ic_drag_handle"
android:clickable="true"
android:paddingTop="@dimen/chooser_edge_margin_normal"
android:tint="?android:attr/textColorSecondary"
android:layout_marginTop="@dimen/chooser_view_spacing"
android:tint="@color/lighter_gray"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true" />
@@ -62,8 +62,8 @@
android:textAppearance="?attr/textAppearanceMedium"
android:textSize="20sp"
android:gravity="center"
android:paddingTop="18dp"
android:paddingBottom="18dp"
android:paddingTop="@dimen/chooser_view_spacing"
android:paddingBottom="@dimen/chooser_view_spacing"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:layout_below="@id/profile_button"

View File

@@ -725,4 +725,5 @@
<dimen name="resolver_icon_size">42dp</dimen>
<dimen name="resolver_badge_size">18dp</dimen>
<dimen name="chooser_target_width">76dp</dimen>
<dimen name="chooser_max_collapsed_height">288dp</dimen>
</resources>

View File

@@ -2771,6 +2771,7 @@
<java-symbol type="dimen" name="chooser_edge_margin_normal" />
<java-symbol type="dimen" name="chooser_preview_image_font_size"/>
<java-symbol type="dimen" name="chooser_preview_width" />
<java-symbol type="dimen" name="chooser_max_collapsed_height" />
<java-symbol type="layout" name="chooser_grid" />
<java-symbol type="layout" name="chooser_grid_preview_text" />
<java-symbol type="layout" name="chooser_grid_preview_image" />

View File

@@ -599,7 +599,7 @@ public class ChooserActivityTest {
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
@@ -629,7 +629,7 @@ public class ChooserActivityTest {
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));