diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f48be0e3242f0..b9f5348027e6e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -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
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index cae1f3831b4a3..76f5099b51a35 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -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;
}
}
diff --git a/core/res/res/drawable/chooser_action_button_bg.xml b/core/res/res/drawable/chooser_action_button_bg.xml
new file mode 100644
index 0000000000000..a434c0b9b6a9b
--- /dev/null
+++ b/core/res/res/drawable/chooser_action_button_bg.xml
@@ -0,0 +1,33 @@
+
+
+
+ -
+
+
+
+
+
+
+
+
+
diff --git a/core/res/res/drawable/ic_content_copy_gm2.xml b/core/res/res/drawable/ic_content_copy_gm2.xml
deleted file mode 100644
index ee58738b75d00..0000000000000
--- a/core/res/res/drawable/ic_content_copy_gm2.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
diff --git a/core/res/res/drawable/ic_menu_copy_material.xml b/core/res/res/drawable/ic_menu_copy_material.xml
index c03723b1fb339..ee58738b75d00 100644
--- a/core/res/res/drawable/ic_menu_copy_material.xml
+++ b/core/res/res/drawable/ic_menu_copy_material.xml
@@ -1,26 +1,25 @@
-
+
-
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
diff --git a/core/res/res/layout/chooser_action_button.xml b/core/res/res/layout/chooser_action_button.xml
new file mode 100644
index 0000000000000..562f188bbc6b5
--- /dev/null
+++ b/core/res/res/layout/chooser_action_button.xml
@@ -0,0 +1,28 @@
+
+
+
diff --git a/core/res/res/layout/chooser_action_row.xml b/core/res/res/layout/chooser_action_row.xml
new file mode 100644
index 0000000000000..ea75611241819
--- /dev/null
+++ b/core/res/res/layout/chooser_action_row.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/core/res/res/layout/chooser_grid_preview_file.xml b/core/res/res/layout/chooser_grid_preview_file.xml
index f7d60c91052db..8605443992881 100644
--- a/core/res/res/layout/chooser_grid_preview_file.xml
+++ b/core/res/res/layout/chooser_grid_preview_file.xml
@@ -65,13 +65,14 @@
android:gravity="start|top"
android:paddingRight="24dp"
android:singleLine="true"/>
-
+
+
diff --git a/core/res/res/layout/chooser_grid_preview_image.xml b/core/res/res/layout/chooser_grid_preview_image.xml
index 79a0de4b271f7..29b7fb4281940 100644
--- a/core/res/res/layout/chooser_grid_preview_image.xml
+++ b/core/res/res/layout/chooser_grid_preview_image.xml
@@ -78,5 +78,14 @@
android:scaleType="centerCrop"/>
+
+
+
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index 9c725b93eec69..5998cff71dfdf 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -37,50 +37,25 @@
-
-
-
-
-
-
+
+
false
+
+
+
false
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a01bbe38f2968..4fdb498451ae9 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -770,4 +770,5 @@
18dp
24dp
1dp
+ 18dp
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 2b0c86b495777..ba64bf00c63a9 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -193,4 +193,7 @@
+
+
+
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8e5230128c066..66ebc7c50fa33 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -66,8 +66,7 @@
-
-
+
@@ -3839,6 +3838,11 @@
+
+
+
+
+
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index c44b7d81868d8..4dfa9bfa7e21b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -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();