В прошлой статье шла речь о работе с PackageManager. Вдогонку к ней расскажу я, как можно реализовать chooser приложений
Допустим, нам нужно выполнить действие с помощью внешней программы. К примеру, открыть страницу в браузере. Для этого мы пишем такой простой код:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.google.com")); startActivity(intent);
И вдруг сложилось так, что браузеров несколько. Тогда после выполнения этого кода мы увидим диалог выбора приложения:
Максимум, что можно здесь поменять — заголовок диалога. Для этого нужно написать следующее:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.google.com")); startActivity(Intent.createChooser(intent, "Каким браузером просмотреть желаете?"));
Результат будет следующим:
Но что, если нам хочется предоставить какой-то другой интерфейс? Тогда нам снова поможет PackageManager
и метод queryIntentActivities
.
Приведу пример реализации chooser-а в виде галереи. На сей раз в качестве экшена будем использовать отправку текста (ACTION_SEND
), т.к. приложений, обрабатывающих его, больше, и будет более наглядно.
private void sendViaCustomChooser() { Intent intent = new Intent(android.content.Intent.ACTION_SEND); intent.setType("text/plain"); PackageManager pm = getPackageManager(); List<ResolveInfo> infos = pm.queryIntentActivities(intent, 0); View dialogView = View.inflate(this, R.layout.custom_chooser, null); final Gallery gallery = (Gallery)dialogView.findViewById(R.id.gallery); gallery.setAdapter(new AppAdapter(pm, infos)); gallery.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ResolveInfo ri = (ResolveInfo)gallery.getAdapter().getItem(position); Intent intent = new Intent(Intent.ACTION_SEND); intent.setClassName(ri.activityInfo.packageName, ri.activityInfo.name); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, "Sample subject"); intent.putExtra(Intent.EXTRA_TEXT, "Sample text"); startActivity(intent); } }); Dialog d = new Dialog(this, android.R.style.Theme_Light_NoTitleBar); d.setContentView(dialogView); d.show(); } private class AppAdapter extends BaseAdapter { List<ResolveInfo> mInfos; PackageManager mPm; private AppAdapter(PackageManager pm, List<ResolveInfo> infos) { this.mInfos = infos; this.mPm = pm; } @Override public int getCount() { return mInfos.size(); } @Override public Object getItem(int position) { return mInfos.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ResolveInfo ri = mInfos.get(position); if (convertView == null) { convertView = View.inflate(StartActivity.this, R.layout.gallery_item, null); } ViewGroup container = (ViewGroup) convertView; ImageView image = (ImageView)container.findViewById(R.id.app_image); image.setImageDrawable(ri.activityInfo.loadIcon(mPm)); TextView title = (TextView)container.findViewById(R.id.app_title); title.setText(ri.activityInfo.loadLabel(mPm)); return container; } }
Здесь довольно много кода, и поэтому то, что относится к PackageManager, выделено.
А результат будет следующим:
Дам кое-какие пояснения. Мы выбрали из всех приложений активности, обрабатывающие экшен ACTION_SEND
. Обратите внимание, что у одного приложения может быть несколько таких активностей (например, приложение ВКонтакте). Потом мы создали на основе этого списка адаптер для галереи. Кроме того, мы обработали событие выбора элемента и запускаем по нему соответствующее приложение.
Обращу внимание на несколько вещей:
- Поле
name
уactivityInfo
— это не заголовок, а имя класса активности. - Заголовок же можно получить с помощью функции
loadLabel
, иконку — с помощьюloadIcon
. - Если хочется получить заголовок самого приложения, а не активности, это можно сделать так: или так:
ri.activityInfo.applicationInfo.loadLabel(mPm)
mPm.getApplicationLabel(ri.activityInfo.applicationInfo)
Заключение
В статье описана возможная реализация собственного AppChooser-а. Если есть другие варианты, прошу высказаться.
3 комментария:
Здравствуйте. Спс за пост. Но вот вопрос: возможно ли запретить (или вообще убрать) из chooser'а какое-нибудь приложение. Например, отправка через блютус.
То есть, я вот не хочу чтобы у пользователя была возможность выбрать другую программу, а только gmail. Возможно ли это?
Тогда не AppChooser нужен, а просто запуск приложения. Этот вопрос рассмотрен в предыдущей статье
здравствуйте, очень позновательный пост.
подскажите можно ли реализовать вот такое:
в choose'ре должны быть только приложения для отправки по email и отправки по sms, потратил день но так и не придумал солюшена.
заранее спсб.
Отправить комментарий