blob: fd000d3c99f3e4c5c2fe1c629c741a8adbbc83ee [file] [log] [blame]
/*
* Copyright (C) 2010 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.
*/
package com.android.providers.downloads.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Parcelable;
import android.provider.BaseColumns;
import android.provider.Downloads;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ListView;
import android.widget.Toast;
import com.android.providers.downloads.Constants;
import com.android.providers.downloads.OpenHelper;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* View showing a list of all downloads the Download Manager knows about.
*/
public class DownloadList extends Activity {
static final String LOG_TAG = "DownloadList";
private ExpandableListView mDateOrderedListView;
private ListView mSizeOrderedListView;
private View mEmptyView;
private DownloadManager mDownloadManager;
private Cursor mDateSortedCursor;
private DateSortedDownloadAdapter mDateSortedAdapter;
private Cursor mSizeSortedCursor;
private DownloadAdapter mSizeSortedAdapter;
private ActionMode mActionMode;
private MyContentObserver mContentObserver = new MyContentObserver();
private MyDataSetObserver mDataSetObserver = new MyDataSetObserver();
private int mStatusColumnId;
private int mIdColumnId;
private int mLocalUriColumnId;
private int mMediaTypeColumnId;
private int mReasonColumndId;
// TODO this shouldn't be necessary
private final Map<Long, SelectionObjAttrs> mSelectedIds =
new HashMap<Long, SelectionObjAttrs>();
private static class SelectionObjAttrs {
private String mFileName;
private String mMimeType;
SelectionObjAttrs(String fileName, String mimeType) {
mFileName = fileName;
mMimeType = mimeType;
}
String getFileName() {
return mFileName;
}
String getMimeType() {
return mMimeType;
}
}
private ListView mCurrentView;
private Cursor mCurrentCursor;
private boolean mCurrentViewIsExpandableListView = false;
private boolean mIsSortedBySize = false;
/**
* We keep track of when a dialog is being displayed for a pending download, because if that
* download starts running, we want to immediately hide the dialog.
*/
private Long mQueuedDownloadId = null;
private AlertDialog mQueuedDialog;
String mSelectedCountFormat;
private Button mSortOption;
private class MyContentObserver extends ContentObserver {
public MyContentObserver() {
super(new Handler());
}
@Override
public void onChange(boolean selfChange) {
handleDownloadsChanged();
}
}
private class MyDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
// ignore change notification if there are selections
if (mSelectedIds.size() > 0) {
return;
}
// may need to switch to or from the empty view
chooseListToShow();
ensureSomeGroupIsExpanded();
}
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setFinishOnTouchOutside(true);
setupViews();
mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
mDownloadManager.setAccessAllDownloads(true);
DownloadManager.Query baseQuery = new DownloadManager.Query()
.setOnlyIncludeVisibleInDownloadsUi(true);
//TODO don't do both queries - do them as needed
mDateSortedCursor = mDownloadManager.query(baseQuery);
mSizeSortedCursor = mDownloadManager.query(baseQuery
.orderBy(DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
DownloadManager.Query.ORDER_DESCENDING));
// only attach everything to the listbox if we can access the download database. Otherwise,
// just show it empty
if (haveCursors()) {
startManagingCursor(mDateSortedCursor);
startManagingCursor(mSizeSortedCursor);
mStatusColumnId =
mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS);
mIdColumnId =
mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID);
mLocalUriColumnId =
mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI);
mMediaTypeColumnId =
mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_MEDIA_TYPE);
mReasonColumndId =
mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON);
mDateSortedAdapter = new DateSortedDownloadAdapter(this, mDateSortedCursor);
mDateOrderedListView.setAdapter(mDateSortedAdapter);
mSizeSortedAdapter = new DownloadAdapter(this, mSizeSortedCursor);
mSizeOrderedListView.setAdapter(mSizeSortedAdapter);
ensureSomeGroupIsExpanded();
}
// did the caller want to display the data sorted by size?
Bundle extras = getIntent().getExtras();
if (extras != null &&
extras.getBoolean(DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, false)) {
mIsSortedBySize = true;
}
mSortOption = (Button) findViewById(R.id.sort_button);
mSortOption.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// flip the view
mIsSortedBySize = !mIsSortedBySize;
// clear all selections
mSelectedIds.clear();
chooseListToShow();
}
});
chooseListToShow();
mSelectedCountFormat = getString(R.string.selected_count);
}
/**
* If no group is expanded in the date-sorted list, expand the first one.
*/
private void ensureSomeGroupIsExpanded() {
mDateOrderedListView.post(new Runnable() {
public void run() {
if (mDateSortedAdapter.getGroupCount() == 0) {
return;
}
for (int group = 0; group < mDateSortedAdapter.getGroupCount(); group++) {
if (mDateOrderedListView.isGroupExpanded(group)) {
return;
}
}
mDateOrderedListView.expandGroup(0);
}
});
}
private void setupViews() {
setContentView(R.layout.download_list);
ModeCallback modeCallback = new ModeCallback(this);
//TODO don't create both views. create only the one needed.
mDateOrderedListView = (ExpandableListView) findViewById(R.id.date_ordered_list);
mDateOrderedListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mDateOrderedListView.setMultiChoiceModeListener(modeCallback);
mDateOrderedListView.setOnChildClickListener(new OnChildClickListener() {
// called when a child is clicked on (this is NOT the checkbox click)
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
if (!(v instanceof DownloadItem)) {
// can this even happen?
return false;
}
if (mSelectedIds.size() > 0) {
((DownloadItem)v).setChecked(true);
} else {
mDateSortedAdapter.moveCursorToChildPosition(groupPosition, childPosition);
handleItemClick(mDateSortedCursor);
}
return true;
}
});
mSizeOrderedListView = (ListView) findViewById(R.id.size_ordered_list);
mSizeOrderedListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mSizeOrderedListView.setMultiChoiceModeListener(modeCallback);
mSizeOrderedListView.setOnItemClickListener(new OnItemClickListener() {
// handle a click from the size-sorted list. (this is NOT the checkbox click)
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mSizeSortedCursor.moveToPosition(position);
handleItemClick(mSizeSortedCursor);
}
});
mEmptyView = findViewById(R.id.empty);
}
private static class ModeCallback implements MultiChoiceModeListener {
private final DownloadList mDownloadList;
public ModeCallback(DownloadList downloadList) {
mDownloadList = downloadList;
}
@Override public void onDestroyActionMode(ActionMode mode) {
mDownloadList.mSelectedIds.clear();
mDownloadList.mActionMode = null;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
if (mDownloadList.haveCursors()) {
final MenuInflater inflater = mDownloadList.getMenuInflater();
inflater.inflate(R.menu.download_menu, menu);
}
mDownloadList.mActionMode = mode;
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (mDownloadList.mSelectedIds.size() == 0) {
// nothing selected.
return true;
}
switch (item.getItemId()) {
case R.id.delete_download:
for (Long downloadId : mDownloadList.mSelectedIds.keySet()) {
mDownloadList.deleteDownload(downloadId);
}
// uncheck all checked items
ListView lv = mDownloadList.getCurrentView();
SparseBooleanArray checkedPositionList = lv.getCheckedItemPositions();
int checkedPositionListSize = checkedPositionList.size();
ArrayList<DownloadItem> sharedFiles = null;
for (int i = 0; i < checkedPositionListSize; i++) {
int position = checkedPositionList.keyAt(i);
if (checkedPositionList.get(position, false)) {
lv.setItemChecked(position, false);
onItemCheckedStateChanged(mode, position, 0, false);
}
}
mDownloadList.mSelectedIds.clear();
// update the subtitle
onItemCheckedStateChanged(mode, 1, 0, false);
break;
case R.id.share_download:
mDownloadList.shareDownloadedFiles();
break;
}
return true;
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
boolean checked) {
// ignore long clicks on groups
if (mDownloadList.isCurrentViewExpandableListView()) {
ExpandableListView ev = mDownloadList.getExpandableListView();
long pos = ev.getExpandableListPosition(position);
if (checked && (ExpandableListView.getPackedPositionType(pos) ==
ExpandableListView.PACKED_POSITION_TYPE_GROUP)) {
// ignore this click
ev.setItemChecked(position, false);
return;
}
}
mDownloadList.setActionModeTitle(mode);
}
}
void setActionModeTitle(ActionMode mode) {
int numSelected = mSelectedIds.size();
if (numSelected > 0) {
mode.setTitle(String.format(mSelectedCountFormat, numSelected,
mCurrentCursor.getCount()));
} else {
mode.setTitle("");
}
}
private boolean haveCursors() {
return mDateSortedCursor != null && mSizeSortedCursor != null;
}
@Override
protected void onResume() {
super.onResume();
if (haveCursors()) {
mDateSortedCursor.registerContentObserver(mContentObserver);
mDateSortedCursor.registerDataSetObserver(mDataSetObserver);
refresh();
}
}
@Override
protected void onPause() {
super.onPause();
if (haveCursors()) {
mDateSortedCursor.unregisterContentObserver(mContentObserver);
mDateSortedCursor.unregisterDataSetObserver(mDataSetObserver);
}
}
private static final String BUNDLE_SAVED_DOWNLOAD_IDS = "download_ids";
private static final String BUNDLE_SAVED_FILENAMES = "filenames";
private static final String BUNDLE_SAVED_MIMETYPES = "mimetypes";
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("isSortedBySize", mIsSortedBySize);
int len = mSelectedIds.size();
if (len == 0) {
return;
}
long[] selectedIds = new long[len];
String[] fileNames = new String[len];
String[] mimeTypes = new String[len];
int i = 0;
for (long id : mSelectedIds.keySet()) {
selectedIds[i] = id;
SelectionObjAttrs obj = mSelectedIds.get(id);
fileNames[i] = obj.getFileName();
mimeTypes[i] = obj.getMimeType();
i++;
}
outState.putLongArray(BUNDLE_SAVED_DOWNLOAD_IDS, selectedIds);
outState.putStringArray(BUNDLE_SAVED_FILENAMES, fileNames);
outState.putStringArray(BUNDLE_SAVED_MIMETYPES, mimeTypes);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mIsSortedBySize = savedInstanceState.getBoolean("isSortedBySize");
mSelectedIds.clear();
long[] selectedIds = savedInstanceState.getLongArray(BUNDLE_SAVED_DOWNLOAD_IDS);
String[] fileNames = savedInstanceState.getStringArray(BUNDLE_SAVED_FILENAMES);
String[] mimeTypes = savedInstanceState.getStringArray(BUNDLE_SAVED_MIMETYPES);
if (selectedIds != null && selectedIds.length > 0) {
for (int i = 0; i < selectedIds.length; i++) {
mSelectedIds.put(selectedIds[i], new SelectionObjAttrs(fileNames[i], mimeTypes[i]));
}
}
chooseListToShow();
}
/**
* Show the correct ListView and hide the other, or hide both and show the empty view.
*/
private void chooseListToShow() {
mDateOrderedListView.setVisibility(View.GONE);
mSizeOrderedListView.setVisibility(View.GONE);
if (mDateSortedCursor == null || mDateSortedCursor.getCount() == 0) {
mEmptyView.setVisibility(View.VISIBLE);
} else {
mEmptyView.setVisibility(View.GONE);
ListView lv = activeListView();
lv.setVisibility(View.VISIBLE);
lv.invalidateViews(); // ensure checkboxes get updated
}
// restore the ActionMode title if there are selections
if (mActionMode != null) {
setActionModeTitle(mActionMode);
}
}
ListView getCurrentView() {
return mCurrentView;
}
ExpandableListView getExpandableListView() {
return mDateOrderedListView;
}
boolean isCurrentViewExpandableListView() {
return mCurrentViewIsExpandableListView;
}
private ListView activeListView() {
if (mIsSortedBySize) {
mCurrentCursor = mSizeSortedCursor;
mCurrentView = mSizeOrderedListView;
setTitle(R.string.download_title_sorted_by_size);
mSortOption.setText(R.string.button_sort_by_date);
mCurrentViewIsExpandableListView = false;
} else {
mCurrentCursor = mDateSortedCursor;
mCurrentView = mDateOrderedListView;
setTitle(R.string.download_title_sorted_by_date);
mSortOption.setText(R.string.button_sort_by_size);
mCurrentViewIsExpandableListView = true;
}
if (mActionMode != null) {
mActionMode.finish();
}
return mCurrentView;
}
/**
* @return an OnClickListener to delete the given downloadId from the Download Manager
*/
private DialogInterface.OnClickListener getDeleteClickHandler(final long downloadId) {
return new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
deleteDownload(downloadId);
}
};
}
/**
* @return an OnClickListener to restart the given downloadId in the Download Manager
*/
private DialogInterface.OnClickListener getRestartClickHandler(final long downloadId) {
return new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mDownloadManager.restartDownload(downloadId);
}
};
}
/**
* Send an Intent to open the download currently pointed to by the given cursor.
*/
private void openCurrentDownload(Cursor cursor) {
final Uri localUri = Uri.parse(cursor.getString(mLocalUriColumnId));
try {
getContentResolver().openFileDescriptor(localUri, "r").close();
} catch (FileNotFoundException exc) {
Log.d(LOG_TAG, "Failed to open download " + cursor.getLong(mIdColumnId), exc);
showFailedDialog(cursor.getLong(mIdColumnId),
getString(R.string.dialog_file_missing_body));
return;
} catch (IOException exc) {
// close() failed, not a problem
}
final long id = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
final Intent intent = OpenHelper.buildViewIntent(this, id);
try {
startActivity(intent);
} catch (ActivityNotFoundException ex) {
Toast.makeText(this, R.string.download_no_application_title, Toast.LENGTH_LONG).show();
}
}
private void handleItemClick(Cursor cursor) {
long id = cursor.getInt(mIdColumnId);
switch (cursor.getInt(mStatusColumnId)) {
case DownloadManager.STATUS_PENDING:
case DownloadManager.STATUS_RUNNING:
sendRunningDownloadClickedBroadcast(id);
break;
case DownloadManager.STATUS_PAUSED:
if (isPausedForWifi(cursor)) {
mQueuedDownloadId = id;
mQueuedDialog = new AlertDialog.Builder(this)
.setTitle(R.string.dialog_title_queued_body)
.setMessage(R.string.dialog_queued_body)
.setPositiveButton(R.string.keep_queued_download, null)
.setNegativeButton(R.string.remove_download, getDeleteClickHandler(id))
.setOnCancelListener(new DialogInterface.OnCancelListener() {
/**
* Called when a dialog for a pending download is canceled.
*/
@Override
public void onCancel(DialogInterface dialog) {
mQueuedDownloadId = null;
mQueuedDialog = null;
}
})
.show();
} else {
sendRunningDownloadClickedBroadcast(id);
}
break;
case DownloadManager.STATUS_SUCCESSFUL:
openCurrentDownload(cursor);
break;
case DownloadManager.STATUS_FAILED:
showFailedDialog(id, getErrorMessage(cursor));
break;
}
}
/**
* @return the appropriate error message for the failed download pointed to by cursor
*/
private String getErrorMessage(Cursor cursor) {
switch (cursor.getInt(mReasonColumndId)) {
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
if (isOnExternalStorage(cursor)) {
return getString(R.string.dialog_file_already_exists);
} else {
// the download manager should always find a free filename for cache downloads,
// so this indicates a strange internal error
return getUnknownErrorMessage();
}
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
if (isOnExternalStorage(cursor)) {
return getString(R.string.dialog_insufficient_space_on_external);
} else {
return getString(R.string.dialog_insufficient_space_on_cache);
}
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
return getString(R.string.dialog_media_not_found);
case DownloadManager.ERROR_CANNOT_RESUME:
return getString(R.string.dialog_cannot_resume);
default:
return getUnknownErrorMessage();
}
}
private boolean isOnExternalStorage(Cursor cursor) {
String localUriString = cursor.getString(mLocalUriColumnId);
if (localUriString == null) {
return false;
}
Uri localUri = Uri.parse(localUriString);
if (!localUri.getScheme().equals("file")) {
return false;
}
String path = localUri.getPath();
String externalRoot = Environment.getExternalStorageDirectory().getPath();
return path.startsWith(externalRoot);
}
private String getUnknownErrorMessage() {
return getString(R.string.dialog_failed_body);
}
private void showFailedDialog(long downloadId, String dialogBody) {
new AlertDialog.Builder(this)
.setTitle(R.string.dialog_title_not_available)
.setMessage(dialogBody)
.setNegativeButton(R.string.delete_download, getDeleteClickHandler(downloadId))
.setPositiveButton(R.string.retry_download, getRestartClickHandler(downloadId))
.show();
}
private void sendRunningDownloadClickedBroadcast(long id) {
final Intent intent = new Intent(Constants.ACTION_LIST);
intent.setPackage(Constants.PROVIDER_PACKAGE_NAME);
intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS,
new long[] { id });
sendBroadcast(intent);
}
// handle a click on one of the download item checkboxes
public void onDownloadSelectionChanged(long downloadId, boolean isSelected,
String fileName, String mimeType) {
if (isSelected) {
mSelectedIds.put(downloadId, new SelectionObjAttrs(fileName, mimeType));
} else {
mSelectedIds.remove(downloadId);
}
}
/**
* Requery the database and update the UI.
*/
private void refresh() {
mDateSortedCursor.requery();
mSizeSortedCursor.requery();
// Adapters get notification of changes and update automatically
}
/**
* Delete a download from the Download Manager.
*/
private void deleteDownload(long downloadId) {
// let DownloadService do the job of cleaning up the downloads db, mediaprovider db,
// and removal of file from sdcard
// TODO do the following in asynctask - not on main thread.
mDownloadManager.markRowDeleted(downloadId);
}
public boolean isDownloadSelected(long id) {
return mSelectedIds.containsKey(id);
}
/**
* Called when there's a change to the downloads database.
*/
void handleDownloadsChanged() {
checkSelectionForDeletedEntries();
if (mQueuedDownloadId != null && moveToDownload(mQueuedDownloadId)) {
if (mDateSortedCursor.getInt(mStatusColumnId) != DownloadManager.STATUS_PAUSED
|| !isPausedForWifi(mDateSortedCursor)) {
mQueuedDialog.cancel();
}
}
}
private boolean isPausedForWifi(Cursor cursor) {
return cursor.getInt(mReasonColumndId) == DownloadManager.PAUSED_QUEUED_FOR_WIFI;
}
/**
* Check if any of the selected downloads have been deleted from the downloads database, and
* remove such downloads from the selection.
*/
private void checkSelectionForDeletedEntries() {
// gather all existing IDs...
Set<Long> allIds = new HashSet<Long>();
for (mDateSortedCursor.moveToFirst(); !mDateSortedCursor.isAfterLast();
mDateSortedCursor.moveToNext()) {
allIds.add(mDateSortedCursor.getLong(mIdColumnId));
}
// ...and check if any selected IDs are now missing
for (Iterator<Long> iterator = mSelectedIds.keySet().iterator(); iterator.hasNext(); ) {
if (!allIds.contains(iterator.next())) {
iterator.remove();
}
}
}
/**
* Move {@link #mDateSortedCursor} to the download with the given ID.
* @return true if the specified download ID was found; false otherwise
*/
private boolean moveToDownload(long downloadId) {
for (mDateSortedCursor.moveToFirst(); !mDateSortedCursor.isAfterLast();
mDateSortedCursor.moveToNext()) {
if (mDateSortedCursor.getLong(mIdColumnId) == downloadId) {
return true;
}
}
return false;
}
/**
* handle share menu button click when one more files are selected for sharing
*/
public boolean shareDownloadedFiles() {
Intent intent = new Intent();
if (mSelectedIds.size() > 1) {
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
ArrayList<Parcelable> attachments = new ArrayList<Parcelable>();
ArrayList<String> mimeTypes = new ArrayList<String>();
for (Map.Entry<Long, SelectionObjAttrs> item : mSelectedIds.entrySet()) {
final Uri uri = ContentUris.withAppendedId(
Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, item.getKey());
final String mimeType = item.getValue().getMimeType();
attachments.add(uri);
if (mimeType != null) {
mimeTypes.add(mimeType);
}
}
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
intent.setType(findCommonMimeType(mimeTypes));
} else {
// get the entry
// since there is ONLY one entry in this, we can do the following
for (Map.Entry<Long, SelectionObjAttrs> item : mSelectedIds.entrySet()) {
final Uri uri = ContentUris.withAppendedId(
Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, item.getKey());
final String mimeType = item.getValue().getMimeType();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType(mimeType);
}
}
intent = Intent.createChooser(intent, getText(R.string.download_share_dialog));
startActivity(intent);
return true;
}
private String findCommonMimeType(ArrayList<String> mimeTypes) {
// are all mimeypes the same?
String str = findCommonString(mimeTypes);
if (str != null) {
return str;
}
// are all prefixes of the given mimetypes the same?
ArrayList<String> mimeTypePrefixes = new ArrayList<String>();
for (String s : mimeTypes) {
mimeTypePrefixes.add(s.substring(0, s.indexOf('/')));
}
str = findCommonString(mimeTypePrefixes);
if (str != null) {
return str + "/*";
}
// return generic mimetype
return "*/*";
}
private String findCommonString(Collection<String> set) {
String str = null;
boolean found = true;
for (String s : set) {
if (str == null) {
str = s;
} else if (!str.equals(s)) {
found = false;
break;
}
}
return (found) ? str : null;
}
}