Action chips in share sheet. (DO NOT MERGE)

Move the Copy button to a new row of chips below the
(now larger) preview. Optionally, if a proximity-sharing
service is installed, show that chip as well.

Bug: 143229724
Fixes: 144290152
Test: atest SystemUITests frameworks/base/core/tests/coretests
Change-Id: I0d6457df85bc937f72ca97da6b4b84b634a90daf
This commit is contained in:
Dan Sandler
2019-11-22 11:58:58 -05:00
committed by Daniel Sandler
parent 3ea014ca6d
commit 0d3e358628
15 changed files with 257 additions and 94 deletions

View File

@@ -8945,6 +8945,14 @@ public final class Settings {
private static final Validator NAVIGATION_MODE_VALIDATOR =
new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"});
/**
* Current provider of proximity-based sharing services.
* Default value in @string/config_defaultNearbySharingComponent.
* No VALIDATOR as this setting will not be backed up.
* @hide
*/
public static final String NEARBY_SHARING_COMPONENT = "nearby_sharing_component";
/**
* Controls whether aware is enabled.
* @hide

View File

@@ -81,6 +81,7 @@ import android.provider.DeviceConfig;
import android.provider.DocumentsContract;
import android.provider.Downloads;
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
import android.service.chooser.IChooserTargetResult;
@@ -103,6 +104,7 @@ import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
@@ -122,6 +124,7 @@ import com.google.android.collect.Lists;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.URISyntaxException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
@@ -152,6 +155,9 @@ public class ChooserActivity extends ResolverActivity {
private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions";
private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label";
private static final String CHIP_ICON_METADATA_KEY = "android.service.chooser.chip_icon";
private static final boolean DEBUG = false;
/**
@@ -515,6 +521,15 @@ public class ChooserActivity extends ResolverActivity {
mIsSuccessfullySelected = false;
Intent intent = getIntent();
Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);
if (targetParcelable instanceof Uri) {
try {
targetParcelable = Intent.parseUri(targetParcelable.toString(),
Intent.URI_INTENT_SCHEME);
} catch (URISyntaxException ex) {
// doesn't parse as an intent; let the next test fail and error out
}
}
if (!(targetParcelable instanceof Intent)) {
Log.w("ChooserActivity", "Target is not an intent: " + targetParcelable);
finish();
@@ -864,6 +879,85 @@ public class ChooserActivity extends ResolverActivity {
}
}
private ComponentName getNearbySharingComponent() {
String nearbyComponent = Settings.Secure.getString(
getContentResolver(),
Settings.Secure.NEARBY_SHARING_COMPONENT);
if (TextUtils.isEmpty(nearbyComponent)) {
nearbyComponent = getString(R.string.config_defaultNearbySharingComponent);
}
if (TextUtils.isEmpty(nearbyComponent)) {
return null;
}
return ComponentName.unflattenFromString(nearbyComponent);
}
private TargetInfo getNearbySharingTarget(Intent originalIntent) {
final ComponentName cn = getNearbySharingComponent();
if (cn == null) return null;
final Intent resolveIntent = new Intent();
resolveIntent.setComponent(cn);
final ResolveInfo ri = getPackageManager().resolveActivity(resolveIntent, 0);
if (ri == null) {
Log.e(TAG, "Device-specified nearby sharing component (" + cn
+ ") not available");
return null;
}
// TODO(b/144290152): CHIP_LABEL_METADATA_KEY / CHIP_ICON_METADATA_KEY
CharSequence name = ri.loadLabel(getPackageManager());
final DisplayResolveInfo dri = new DisplayResolveInfo(
originalIntent, ri, name, "", null);
dri.setDisplayIcon(ri.loadIcon(getPackageManager()));
return dri;
}
private Button createActionButton(Drawable icon, CharSequence title, View.OnClickListener r) {
Button b = (Button) LayoutInflater.from(this).inflate(R.layout.chooser_action_button, null);
if (icon != null) {
final int size = getResources()
.getDimensionPixelSize(R.dimen.chooser_action_button_icon_size);
icon.setBounds(0, 0, size, size);
b.setCompoundDrawablesRelative(icon, null, null, null);
}
b.setText(title);
b.setOnClickListener(r);
return b;
}
private Button createCopyButton() {
final Button b = createActionButton(
getDrawable(R.drawable.ic_menu_copy_material),
getString(R.string.copy), this::onCopyButtonClicked);
b.setId(R.id.chooser_copy_button);
return b;
}
private @Nullable Button createNearbyButton(Intent originalIntent) {
final TargetInfo ti = getNearbySharingTarget(originalIntent);
if (ti == null) return null;
return createActionButton(
ti.getDisplayIcon(),
ti.getDisplayLabel(),
(View unused) -> safelyStartActivity(ti)
);
}
private void addActionButton(ViewGroup parent, Button b) {
if (b == null) return;
final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
final int gap = getResources().getDimensionPixelSize(R.dimen.resolver_icon_margin) / 2;
lp.setMarginsRelative(gap, 0, gap, 0);
parent.addView(b, lp);
}
private ViewGroup displayContentPreview(@ContentPreviewType int previewType,
Intent targetIntent, LayoutInflater layoutInflater, ViewGroup convertView,
ViewGroup parent) {
@@ -897,8 +991,10 @@ public class ChooserActivity extends ResolverActivity {
ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
R.layout.chooser_grid_preview_text, parent, false);
contentPreviewLayout.findViewById(R.id.copy_button).setOnClickListener(
this::onCopyButtonClicked);
final ViewGroup actionRow =
(ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
addActionButton(actionRow, createCopyButton());
addActionButton(actionRow, createNearbyButton(targetIntent));
CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
if (sharingText == null) {
@@ -1056,7 +1152,8 @@ public class ChooserActivity extends ResolverActivity {
// TODO(b/120417119): Disable file copy until after moving to sysui,
// due to permissions issues
contentPreviewLayout.findViewById(R.id.file_copy_button).setVisibility(View.GONE);
//((ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row))
// .addView(createCopyButton());
String action = targetIntent.getAction();
if (Intent.ACTION_SEND.equals(action)) {
@@ -1507,7 +1604,7 @@ public class ChooserActivity extends ResolverActivity {
}
return new IntentFilter(intent.getAction(), dataString);
} catch (Exception e) {
Log.e(TAG, "failed to get target intent filter " + e);
Log.e(TAG, "failed to get target intent filter", e);
return null;
}
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2019 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
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/lighter_gray">
<item>
<inset
android:insetLeft="0dp"
android:insetTop="8dp"
android:insetRight="0dp"
android:insetBottom="8dp">
<shape android:shape="rectangle">
<corners android:radius="16dp"></corners>
<stroke android:width="1dp"
android:color="?attr/textColorSecondary" />
<solid android:color="?attr/colorBackground" />
</shape>
</inset>
</item>
</ripple>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:attr/textColorSecondary"
android:pathData="M18,21L4,21L4,7L2,7v14c0,1.1 0.9,2 2,2h14v-2zM21,17L21,3c0,-1.1 -0.9,-2 -2,-2L8,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2zM19,17L8,17L8,3h11v14z"/>
</vector>

View File

@@ -1,26 +1,25 @@
<!--
Copyright (C) 2014 The Android Open Source Project
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 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
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
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.
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal">
<path
android:pathData="M16,1L4,1C2.9,1 2,1.9 2,3l0,14l2,0L4,3l12,0L16,1zM19,5L8,5C6.9,5 6,5.9 6,7l0,14c0,1.1 0.9,2 2,2l11,0c1.1,0 2,-0.9 2,-2L21,7C21,5.9 20.1,5 19,5zM19,21L8,21L8,7l11,0L19,21z"
android:fillColor="@color/white"/>
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:attr/textColorSecondary"
android:pathData="M18,21L4,21L4,7L2,7v14c0,1.1 0.9,2 2,2h14v-2zM21,17L21,3c0,-1.1 -0.9,-2 -2,-2L8,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2zM19,17L8,17L8,3h11v14z"/>
</vector>

View File

@@ -0,0 +1,28 @@
<!--
~ Copyright (C) 2019 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
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center_vertical|start"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:drawablePadding="8dp"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
android:maxWidth="192dp"
android:singleLine="true"
android:clickable="true"
android:background="@drawable/chooser_action_button_bg"
/>

View File

@@ -0,0 +1,26 @@
<!--
~ Copyright (C) 2019 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
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/chooser_edge_margin_normal"
android:paddingRight="@dimen/chooser_edge_margin_normal"
android:gravity="center"
>
</LinearLayout>

View File

@@ -65,13 +65,14 @@
android:gravity="start|top"
android:paddingRight="24dp"
android:singleLine="true"/>
<Button
android:id="@+id/file_copy_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:gravity="center"
android:layout_gravity="center_vertical"
android:background="@drawable/ic_content_copy_gm2"/>
</LinearLayout>
<include
android:id="@+id/chooser_action_row"
layout="@layout/chooser_action_row"
android:layout_width="@dimen/chooser_preview_width"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/chooser_view_spacing"
/>
</LinearLayout>

View File

@@ -78,5 +78,14 @@
android:scaleType="centerCrop"/>
</RelativeLayout>
<include
android:id="@+id/chooser_action_row"
layout="@layout/chooser_action_row"
android:layout_width="@dimen/chooser_preview_width"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/chooser_view_spacing"
/>
</LinearLayout>

View File

@@ -37,50 +37,25 @@
<TextView
android:id="@+id/content_preview_text"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_toStartOf="@id/copy_button"
android:layout_centerVertical="true"
android:ellipsize="end"
android:fontFamily="@android:string/config_headlineFontFamily"
android:textColor="?android:attr/textColorPrimary"
android:maxLines="2"/>
<LinearLayout
android:id="@+id/copy_button"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="@dimen/chooser_view_spacing"
android:gravity="center"
android:minWidth="48dp"
android:minHeight="48dp"
android:clickable="true"
style="?attr/borderlessButtonStyle">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:gravity="top|center_horizontal"
android:src="@drawable/ic_content_copy_gm2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:gravity="center_horizontal"
android:text="@string/copy"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
android:maxWidth="72dp"
android:maxLines="2"
android:ellipsize="end" />
</LinearLayout>
</RelativeLayout>
<include
android:id="@+id/chooser_action_row"
layout="@layout/chooser_action_row"
android:layout_width="@dimen/chooser_preview_width"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/chooser_view_spacing"
/>
<!-- Required sub-layout so we can get the nice rounded corners-->
<!-- around this section -->
<LinearLayout

View File

@@ -4261,6 +4261,10 @@
to have a confirmed way to dismiss the keyboard when desired. -->
<bool name="config_automotiveHideNavBarForKeyboard">false</bool>
<!-- Component name that accepts ACTION_SEND intents for nearby (proximity-based) sharing.
Used by ChooserActivity. -->
<string translatable="false" name="config_defaultNearbySharingComponent"></string>
<!-- Boolean indicating whether frameworks needs to reset cell broadcast geo-fencing
check after reboot or airplane mode toggling -->
<bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool>

View File

@@ -770,4 +770,5 @@
<dimen name="resolver_small_margin">18dp</dimen>
<dimen name="resolver_edge_margin">24dp</dimen>
<dimen name="resolver_elevation">1dp</dimen>
<dimen name="chooser_action_button_icon_size">18dp</dimen>
</resources>

View File

@@ -193,4 +193,7 @@
<!-- A tag used to save the index where the custom view is stored -->
<item type="id" name="notification_custom_view_index_tag" />
<!-- Marks the "copy to clipboard" button in the ChooserActivity -->
<item type="id" name="chooser_copy_button" />
</resources>

View File

@@ -66,8 +66,7 @@
<java-symbol type="id" name="content_preview_text_layout" />
<java-symbol type="id" name="content_preview_title" />
<java-symbol type="id" name="content_preview_title_layout" />
<java-symbol type="id" name="copy_button" />
<java-symbol type="id" name="file_copy_button" />
<java-symbol type="id" name="chooser_action_row" />
<java-symbol type="id" name="current_scene" />
<java-symbol type="id" name="scene_layoutid_cache" />
<java-symbol type="id" name="customPanel" />
@@ -3839,6 +3838,11 @@
<java-symbol type="drawable" name="android_logotype" />
<java-symbol type="layout" name="platlogo_layout" />
<java-symbol type="id" name="chooser_copy_button" />
<java-symbol type="layout" name="chooser_action_button" />
<java-symbol type="dimen" name="chooser_action_button_icon_size" />
<java-symbol type="string" name="config_defaultNearbySharingComponent" />
<java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" />
<java-symbol type="bool" name="reset_geo_fencing_check_after_boot_or_apm" />
</resources>

View File

@@ -469,8 +469,8 @@ public class ChooserActivityTest {
.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
onView(withId(R.id.copy_button)).check(matches(isDisplayed()));
onView(withId(R.id.copy_button)).perform(click());
onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed()));
onView(withId(R.id.chooser_copy_button)).perform(click());
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
Context.CLIPBOARD_SERVICE);
ClipData clipData = clipboard.getPrimaryClip();