Code:
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_HOME);
Intent chooser = Intent.createChooser(launchInten
This should work for early versions of Android.
Use intent PICKER instead of CHOOSER. The difference is that picker won't start the target intent automatically, but rather, it returns to onActivityResult() the target intent with the selected app's component name attached. Then you start the target intent in the callback as a 2nd step.
A little bit of code should explain,
// In MyActivity class
static final int REQUEST_CODE_MY_PICK = 1;
// Getting ready to start intent. Note: call startActivityForResult()
... launchIntent = the target intent you want to start;
Intent intentPick = new Intent();
intentPick.setAction(Intent.ACTION_PICK_ACTIVITY);
intentPick.putExtra(Intent.EXTRA_TITLE, "Launch using");
intentPick.putExtra(Intent.EXTRA_INTENT, launchIntent);
this.startActivityForResult(intentPick, REQUEST_CODE_MY_PICK);
// You have just started a picker activity,
// let's see what user will pick in the following callback
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == REQUEST_CODE_MY_PICK) {
String appName = data.getComponent().flattenToShortString();
// Now you know the app being picked.
// data is a copy of your launchIntent with this important extra info added.
// Don't forget to start it!
startActivity(data);
}
}
On Android 5.1+, you can use the three-parameter edition of the createChooser() method, where the last parameter is an IntentSender that you can use to find out what was chosen.
Prior to Android 5.1, there is nothing in Android to let you know what the user chose.
The answer provided by BinHe works but the problem is that a big number of apps is shown. In this solution I use the Intent.ACTION_PICK_ACTIVITY but only the apps compatible with Intent.ACTION_SEND will be shown, and you will know which option the user selected.
public void doSocialShare(String title, String text, String url){
// First search for compatible apps with sharing (Intent.ACTION_SEND)
List<Intent> targetedShareIntents = new ArrayList<Intent>();
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType("text/plain");
// Set title and text to share when the user selects an option.
shareIntent.putExtra(Intent.EXTRA_TITLE, title);
shareIntent.putExtra(Intent.EXTRA_TEXT, url);
shareIntent.putExtra(Intent.EXTRA_TEXT, text);
List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(shareIntent, 0);
if (!resInfo.isEmpty()) {
for (ResolveInfo info : resInfo) {
Intent targetedShare = new Intent(android.content.Intent.ACTION_SEND);
targetedShare.setType("text/plain"); // put here your mime type
targetedShare.setPackage(info.activityInfo.packageName.toLowerCase());
targetedShareIntents.add(targetedShare);
}
// Then show the ACTION_PICK_ACTIVITY to let the user select it
Intent intentPick = new Intent();
intentPick.setAction(Intent.ACTION_PICK_ACTIVITY);
// Set the title of the dialog
intentPick.putExtra(Intent.EXTRA_TITLE, title);
intentPick.putExtra(Intent.EXTRA_INTENT, shareIntent);
intentPick.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray());
// Call StartActivityForResult so we can get the app name selected by the user
this.startActivityForResult(intentPick, REQUEST_CODE_MY_PICK);
}
}
Finally, to be able to get the app selected by the user you must override the onActivityResult on your activity:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE_MY_PICK) {
if(data != null && data.getComponent() != null && !TextUtils.isEmpty(data.getComponent().flattenToShortString()) ) {
String appName = data.getComponent().flattenToShortString();
// Now you know the app being picked.
// data is a copy of your launchIntent with this important extra info added.
// Start the selected activity
startActivity(data);
}
}
}
I did in different way, no need to implement custom component:
Send Intent:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "My feature text");
sendIntent.setType("text/plain");
Intent receiver = new Intent(this, ApplicationSelectorReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, receiver, PendingIntent.FLAG_UPDATE_CURRENT);
Intent chooser = Intent.createChooser(sendIntent, null, pendingIntent.getIntentSender());
startActivity(chooser);
Add BroadcastReceiver ApplicationSelectorReceiver.class
in manifest.
<receiver android:name=".ApplicationSelectorReceiver"></receiver>
ApplicationSelectorReceiver.java
public class ApplicationSelectorReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
for (String key : Objects.requireNonNull(intent.getExtras()).keySet()) {
try {
ComponentName componentInfo = (ComponentName) intent.getExtras().get(key);
PackageManager packageManager = context.getPackageManager();
assert componentInfo != null;
String appName = (String) packageManager.getApplicationLabel(packageManager.getApplicationInfo(componentInfo.getPackageName(), PackageManager.GET_META_DATA));
Log.i("Selected Application Name", appName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Result:
Gmail
Facebook
Hangouts
Instagram
Drive
Hope this would help others.
The CommonsWare's solution only works from Android 5.1 (API level 22). Here is my solution to work with all Android versions, by creating our own app chooser dialog.
Step 1: Create a custom layout for the app chooser dialog.
dialog_app_chooser.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/text_view_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingStart="20dp"
android:paddingTop="14dp"
android:paddingEnd="0dp"
android:paddingBottom="14dp"
android:text="Select an action"
android:textColor="#000"
android:textSize="16sp"
android:textStyle="bold" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view_apps"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="16dp"
android:paddingEnd="16dp" />
</LinearLayout>
Step 2: Create a layout for an item in app chooser dialog.
item_app.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/image_view_app_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/text_view_app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:textColor="#000"
android:textSize="12sp" />
</LinearLayout>
Step 3: Create a model class which indicates an app in the app chooser dialog.
App.java
public class App implements Parcelable {
public Intent intent;
public ResolveInfo resolveInfo;
public App(Intent intent, ResolveInfo resolveInfo) {
this.intent = intent;
this.resolveInfo = resolveInfo;
}
protected App(Parcel in) {
intent = in.readParcelable(Intent.class.getClassLoader());
resolveInfo = in.readParcelable(ResolveInfo.class.getClassLoader());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(intent, flags);
dest.writeParcelable(resolveInfo, flags);
}
public static final Creator<App> CREATOR = new Creator<App>() {
@Override
public App createFromParcel(Parcel in) {
return new App(in);
}
@Override
public App[] newArray(int size) {
return new App[size];
}
};
}
Step 4: Create a custom adapter which display all apps in the app chooser dialog.
AppAdapter.java
public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> {
private List<App> apps;
private OnItemClickListener listener;
public AppAdapter(List<App> apps, OnItemClickListener listener) {
this.apps = apps;
this.listener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app, parent, false);
return new ViewHolder(view, listener);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
App app = apps.get(viewHolder.getAdapterPosition());
viewHolder.bind(app);
}
@Override
public int getItemCount() {
return apps.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
private ImageView appIcon;
private TextView appName;
private App app;
ViewHolder(View itemView, final OnItemClickListener listener) {
super(itemView);
appIcon = itemView.findViewById(R.id.image_view_app_icon);
appName = itemView.findViewById(R.id.text_view_app_name);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick(app);
}
});
}
void bind(App app) {
this.app = app;
PackageManager packageManager = appName.getContext().getPackageManager();
appIcon.setImageDrawable(app.resolveInfo.loadIcon(packageManager));
appName.setText(app.resolveInfo.loadLabel(packageManager));
}
}
interface OnItemClickListener {
void onItemClick(App app);
}
}
Step 5: Create the app chooser dialog.
AppChooserDialog.java
public class AppChooserDialog extends BottomSheetDialogFragment implements AppAdapter.OnItemClickListener {
private static final String KEY_APPS = "KEY_APPS";
private static final String KEY_TITLE = "KEY_TITLE";
private static final String KEY_REQUEST_CODE = "KEY_REQUEST_CODE";
public static void show(AppCompatActivity activity, ArrayList<Intent> targets, String title, int requestCode) {
PackageManager packageManager = activity.getPackageManager();
ArrayList<App> apps = new ArrayList<>();
for (Intent intent : targets) {
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : activities) {
Intent targetIntent = new Intent(intent);
apps.add(new App(targetIntent, resolveInfo));
}
}
if (apps.size() > 0) {
if (apps.size() == 1) {
activity.startActivityForResult(apps.get(0).intent, requestCode);
} else {
DialogFragment appChooserDialog = new AppChooserDialog();
Bundle data = new Bundle();
data.putParcelableArrayList(KEY_APPS, apps);
data.putString(KEY_TITLE, title);
data.putInt(KEY_REQUEST_CODE, requestCode);
appChooserDialog.setArguments(data);
appChooserDialog.show(activity.getSupportFragmentManager(), "AppChooserDialog");
}
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.dialog_app_chooser, container, false);
TextView titleTextView = rootView.findViewById(R.id.text_view_title);
RecyclerView appsRecyclerView = rootView.findViewById(R.id.recycler_view_apps);
String title = getArguments().getString(KEY_TITLE);
if (!TextUtils.isEmpty(title)) {
titleTextView.setText(title);
}
List<App> apps = getArguments().getParcelableArrayList(KEY_APPS);
appsRecyclerView.setAdapter(new AppAdapter(apps, this));
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
float screenWidthInDp = displayMetrics.widthPixels / displayMetrics.density;
int recyclerViewItemWidthInDp = 72;
int recyclerViewStartEndPadding = 32;
int numberOfColumns = (int) ((screenWidthInDp - recyclerViewStartEndPadding) / recyclerViewItemWidthInDp);
int spanCount = (apps.size() < numberOfColumns) ? apps.size() : numberOfColumns;
appsRecyclerView.setLayoutManager(new GridLayoutManager(requireActivity(), spanCount));
return rootView;
}
@Override
public void onItemClick(App app) {
ActivityInfo activity = app.resolveInfo.activityInfo;
String packageName = activity.applicationInfo.packageName;
ComponentName component = new ComponentName(packageName, activity.name);
Intent intent = new Intent(app.intent);
intent.setComponent(component);
Uri uri = app.intent.getParcelableExtra(MediaStore.EXTRA_OUTPUT);
if (uri != null) {
requireActivity().grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
OnAppSelectedListener listener = null;
try {
listener = (OnAppSelectedListener) requireActivity();
} catch (Exception e) {
// Ignore exception
}
if (listener != null) {
listener.onAppSelected(intent);
}
requireActivity().startActivityForResult(intent, getArguments().getInt(KEY_REQUEST_CODE));
dismiss();
}
public interface OnAppSelectedListener {
void onAppSelected(Intent intent);
}
}
Step 6: Using the app chooser dialog from an activity.
public class MainActivity extends AppCompatActivity implements AppChooserDialog.OnAppSelectedListener {
private static final int REQUEST_CODE_PICK_IMAGE = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<Intent> intents = new ArrayList<>();
Intent pickImageIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intents.add(pickImageIntent);
AppChooserDialog.show(this, intents, "Pick image from", REQUEST_CODE_PICK_IMAGE);
}
@Override
public void onAppSelected(Intent intent) {
ComponentName componentName = intent.getComponent();
String packageName = componentName.getPackageName();
String activityName = componentName.getClassName();
Log.i("TAG", "packageName = " + packageName + ", activityName = " + activityName);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_PICK_IMAGE) {
Log.i("TAG", "onActivityResult");
// TODO: Put your logic here.
}
}
}
The result: