blob: 2e85481fb42599eaa9f978352697658ffd1d967f [file] [log] [blame]
package org.wordpress.android.ui.media;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.MenuItemCompat.OnActionExpandListener;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SearchView.OnQueryTextListener;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.Toast;
import org.wordpress.android.R;
import org.wordpress.android.WordPress;
import org.wordpress.android.models.FeatureSet;
import org.wordpress.android.ui.ActivityId;
import org.wordpress.android.ui.media.MediaEditFragment.MediaEditFragmentCallback;
import org.wordpress.android.ui.media.MediaGridFragment.Filter;
import org.wordpress.android.ui.media.MediaGridFragment.MediaGridListener;
import org.wordpress.android.ui.media.MediaItemFragment.MediaItemFragmentCallback;
import org.wordpress.android.ui.media.services.MediaDeleteService;
import org.wordpress.android.ui.media.services.MediaEvents;
import org.wordpress.android.util.ActivityUtils;
import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.util.PermissionUtils;
import org.wordpress.android.util.ToastUtils;
import org.xmlrpc.android.ApiHelper;
import org.xmlrpc.android.ApiHelper.GetFeatures.Callback;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import de.greenrobot.event.EventBus;
/**
* The main activity in which the user can browse their media.
*/
public class MediaBrowserActivity extends AppCompatActivity implements MediaGridListener,
MediaItemFragmentCallback, OnQueryTextListener, OnActionExpandListener,
MediaEditFragmentCallback {
private static final String SAVED_QUERY = "SAVED_QUERY";
public static final int MEDIA_PERMISSION_REQUEST_CODE = 1;
private MediaGridFragment mMediaGridFragment;
private MediaItemFragment mMediaItemFragment;
private MediaEditFragment mMediaEditFragment;
private MediaAddFragment mMediaAddFragment;
private PopupWindow mAddMediaPopup;
private SearchView mSearchView;
private MenuItem mSearchMenuItem;
private Menu mMenu;
private FeatureSet mFeatureSet;
private String mQuery;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
// Coming from zero connection. Continue what's pending for delete
int blogId = WordPress.getCurrentLocalTableBlogId();
if (blogId != -1 && WordPress.wpDB.hasMediaDeleteQueueItems(blogId)) {
startMediaDeleteService();
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This should be removed when #2734 is fixed
if (WordPress.getCurrentBlog() == null) {
ToastUtils.showToast(this, R.string.blog_not_found, ToastUtils.Duration.SHORT);
finish();
return;
}
setContentView(R.layout.media_browser_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.media);
FragmentManager fm = getFragmentManager();
fm.addOnBackStackChangedListener(mOnBackStackChangedListener);
FragmentTransaction ft = fm.beginTransaction();
mMediaAddFragment = (MediaAddFragment) fm.findFragmentById(R.id.mediaAddFragment);
mMediaGridFragment = (MediaGridFragment) fm.findFragmentById(R.id.mediaGridFragment);
mMediaItemFragment = (MediaItemFragment) fm.findFragmentByTag(MediaItemFragment.TAG);
if (mMediaItemFragment != null)
ft.hide(mMediaGridFragment);
mMediaEditFragment = (MediaEditFragment) fm.findFragmentByTag(MediaEditFragment.TAG);
if (mMediaEditFragment != null && !mMediaEditFragment.isInLayout())
ft.hide(mMediaItemFragment);
ft.commitAllowingStateLoss();
setupAddMenuPopup();
String action = getIntent().getAction();
if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
// We arrived here from a share action
uploadSharedFiles();
}
}
@Override
public void onStart() {
super.onStart();
registerReceiver(mReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
unregisterReceiver(mReceiver);
super.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVED_QUERY, mQuery);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mQuery = savedInstanceState.getString(SAVED_QUERY);
}
private void uploadSharedFiles() {
Intent intent = getIntent();
String action = intent.getAction();
final List<Uri> multi_stream;
if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
multi_stream = intent.getParcelableArrayListExtra((Intent.EXTRA_STREAM));
} else {
multi_stream = new ArrayList<>();
multi_stream.add((Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM));
}
mMediaAddFragment.uploadList(multi_stream);
// clear the intent's action, so that in case the user rotates, we don't re-upload the same
// files
getIntent().setAction(null);
}
private final FragmentManager.OnBackStackChangedListener mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
FragmentManager manager = getFragmentManager();
MediaGridFragment mediaGridFragment = (MediaGridFragment)manager.findFragmentById(R.id.mediaGridFragment);
if (mediaGridFragment.isVisible()) {
mediaGridFragment.refreshSpinnerAdapter();
}
ActivityUtils.hideKeyboard(MediaBrowserActivity.this);
}
};
/** Setup the popup that allows you to add new media from camera, video camera or local files **/
private void setupAddMenuPopup() {
String capturePhoto = getResources().getString(R.string.media_add_popup_capture_photo);
String captureVideo = getResources().getString(R.string.media_add_popup_capture_video);
String pickPhotoFromGallery = getResources().getString(R.string.select_photo);
String pickVideoFromGallery = getResources().getString(R.string.select_video);
final ArrayAdapter<String> adapter = new ArrayAdapter<>(MediaBrowserActivity.this,
R.layout.actionbar_add_media_cell,
new String[] {
capturePhoto, captureVideo, pickPhotoFromGallery, pickVideoFromGallery
});
View layoutView = getLayoutInflater().inflate(R.layout.actionbar_add_media, null, false);
ListView listView = (ListView) layoutView.findViewById(R.id.actionbar_add_media_listview);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
adapter.notifyDataSetChanged();
if (position == 0) {
mMediaAddFragment.launchCamera();
} else if (position == 1) {
mMediaAddFragment.launchVideoCamera();
} else if (position == 2) {
mMediaAddFragment.launchPictureLibrary();
} else if (position == 3) {
mMediaAddFragment.launchVideoLibrary();
}
mAddMediaPopup.dismiss();
}
});
int width = getResources().getDimensionPixelSize(R.dimen.action_bar_spinner_width);
mAddMediaPopup = new PopupWindow(layoutView, width, ViewGroup.LayoutParams.WRAP_CONTENT, true);
mAddMediaPopup.setBackgroundDrawable(new ColorDrawable());
}
@Override
protected void onResume() {
super.onResume();
startMediaDeleteService();
getFeatureSet();
ActivityId.trackLastActivity(ActivityId.MEDIA);
}
/** Get the feature set for a wordpress.com hosted blog **/
private void getFeatureSet() {
if (WordPress.getCurrentBlog() == null || !WordPress.getCurrentBlog().isDotcomFlag())
return;
ApiHelper.GetFeatures task = new ApiHelper.GetFeatures(new Callback() {
@Override
public void onResult(FeatureSet featureSet) {
mFeatureSet = featureSet;
}
});
List<Object> apiArgs = new ArrayList<>();
apiArgs.add(WordPress.getCurrentBlog());
task.execute(apiArgs);
}
@Override
protected void onPause() {
super.onPause();
if (mSearchMenuItem != null) {
String tempQuery = mQuery;
MenuItemCompat.collapseActionView(mSearchMenuItem);
mQuery = tempQuery;
}
}
@Override
public void onMediaItemSelected(String mediaId) {
String tempQuery = mQuery;
if (mSearchView != null) {
mSearchView.clearFocus();
}
if (mSearchMenuItem != null) {
MenuItemCompat.collapseActionView(mSearchMenuItem);
}
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() == 0) {
FragmentTransaction ft = fm.beginTransaction();
ft.hide(mMediaGridFragment);
mMediaGridFragment.clearSelectedItems();
mMediaItemFragment = MediaItemFragment.newInstance(mediaId);
ft.add(R.id.media_browser_container, mMediaItemFragment, MediaItemFragment.TAG);
ft.addToBackStack(null);
ft.commitAllowingStateLoss();
mQuery = tempQuery;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
mMenu = menu;
getMenuInflater().inflate(R.menu.media, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
mSearchView.setOnQueryTextListener(this);
mSearchMenuItem = menu.findItem(R.id.menu_search);
MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, this);
//open search bar if we were searching for something before
if (!TextUtils.isEmpty(mQuery) && mMediaGridFragment != null && mMediaGridFragment.isVisible()) {
String tempQuery = mQuery; //temporary hold onto query
MenuItemCompat.expandActionView(mSearchMenuItem); //this will reset mQuery
onQueryTextSubmit(tempQuery);
mSearchView.setQuery(mQuery, true);
}
return super.onPrepareOptionsMenu(menu);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
switch (requestCode) {
case MEDIA_PERMISSION_REQUEST_CODE:
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
ToastUtils.showToast(this, getString(R.string.add_media_permission_required));
return;
}
}
showNewMediaMenu();
break;
default:
break;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int i = item.getItemId();
if (i == android.R.id.home) {
onBackPressed();
return true;
} else if (i == R.id.menu_new_media) {
if (PermissionUtils.checkAndRequestCameraAndStoragePermissions(this, MEDIA_PERMISSION_REQUEST_CODE)) {
showNewMediaMenu();
}
return true;
} else if (i == R.id.menu_search) {
mSearchMenuItem = item;
MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, this);
MenuItemCompat.expandActionView(mSearchMenuItem);
mSearchView = (SearchView) item.getActionView();
mSearchView.setOnQueryTextListener(this);
// load last saved query
if (!TextUtils.isEmpty(mQuery)) {
onQueryTextSubmit(mQuery);
mSearchView.setQuery(mQuery, true);
}
return true;
} else if (i == R.id.menu_edit_media) {
String mediaId = mMediaItemFragment.getMediaId();
FragmentManager fm = getFragmentManager();
if (mMediaEditFragment == null || !mMediaEditFragment.isInLayout()) {
// phone layout: hide item details, show and update edit fragment
FragmentTransaction ft = fm.beginTransaction();
if (mMediaItemFragment.isVisible())
ft.hide(mMediaItemFragment);
mMediaEditFragment = MediaEditFragment.newInstance(mediaId);
ft.add(R.id.media_browser_container, mMediaEditFragment, MediaEditFragment.TAG);
ft.addToBackStack(null);
ft.commitAllowingStateLoss();
} else {
// tablet layout: update edit fragment
mMediaEditFragment.loadMedia(mediaId);
}
if (mSearchView != null) {
mSearchView.clearFocus();
}
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onMediaItemListDownloaded() {
if (mMediaItemFragment != null) {
mMediaGridFragment.setRefreshing(false);
if (mMediaItemFragment.isInLayout()) {
mMediaItemFragment.loadDefaultMedia();
}
}
}
@Override
public void onMediaItemListDownloadStart() {
mMediaGridFragment.setRefreshing(true);
}
@Override
public boolean onQueryTextSubmit(String query) {
if (mMediaGridFragment != null) {
mMediaGridFragment.search(query);
}
mQuery = query;
mSearchView.clearFocus();
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
if (mMediaGridFragment != null) {
mMediaGridFragment.search(newText);
}
mQuery = newText;
return true;
}
@Override
public void onResume(Fragment fragment) {
invalidateOptionsMenu();
}
@Override
public void onPause(Fragment fragment) {
invalidateOptionsMenu();
}
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
// currently we don't support searching from within a filter, so hide it
if (mMediaGridFragment != null) {
mMediaGridFragment.setFilterVisibility(View.GONE);
mMediaGridFragment.setFilter(Filter.ALL);
}
// load last search query
if (!TextUtils.isEmpty(mQuery))
onQueryTextChange(mQuery);
mMenu.findItem(R.id.menu_new_media).setVisible(false);
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
if (mMediaGridFragment != null) {
mMediaGridFragment.setFilterVisibility(View.VISIBLE);
mMediaGridFragment.setFilter(Filter.ALL);
}
mMenu.findItem(R.id.menu_new_media).setVisible(true);
return true;
}
public void onSavedEdit(String mediaId, boolean result) {
if (mMediaEditFragment != null && mMediaEditFragment.isVisible() && result) {
FragmentManager fm = getFragmentManager();
fm.popBackStack();
// refresh media item details (phone-only)
if (mMediaItemFragment != null)
mMediaItemFragment.loadMedia(mediaId);
// refresh grid
mMediaGridFragment.refreshMediaFromDB();
}
}
private void startMediaDeleteService() {
if (NetworkUtils.isNetworkAvailable(this)) {
startService(new Intent(this, MediaDeleteService.class));
}
}
@Override
public void onBackPressed() {
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
} else {
super.onBackPressed();
}
}
@SuppressWarnings("unused")
public void onEventMainThread(MediaEvents.MediaChanged event) {
updateOnMediaChanged(event.mLocalBlogId, event.mMediaId);
}
@SuppressWarnings("unused")
public void onEventMainThread(MediaEvents.MediaUploadSucceeded event) {
updateOnMediaChanged(event.mLocalBlogId, event.mLocalMediaId);
}
@SuppressWarnings("unused")
public void onEventMainThread(MediaEvents.MediaUploadFailed event) {
ToastUtils.showToast(this, event.mErrorMessage, ToastUtils.Duration.LONG);
}
public void updateOnMediaChanged(String blogId, String mediaId) {
if (mediaId == null) {
return;
}
// If the media was deleted, remove it from multi select (if it was selected) and hide it from the the detail
// view (if it was the one displayed)
if (!WordPress.wpDB.mediaFileExists(blogId, mediaId)) {
mMediaGridFragment.removeFromMultiSelect(mediaId);
if (mMediaEditFragment != null && mMediaEditFragment.isVisible()
&& mediaId.equals(mMediaEditFragment.getMediaId())) {
if (mMediaEditFragment.isInLayout()) {
mMediaEditFragment.loadMedia(null);
} else {
getFragmentManager().popBackStack();
}
}
}
// Update Grid view
mMediaGridFragment.refreshMediaFromDB();
// Update Spinner views
mMediaGridFragment.updateFilterText();
mMediaGridFragment.updateSpinnerAdapter();
}
@Override
public void onRetryUpload(String mediaId) {
mMediaAddFragment.addToQueue(mediaId);
}
public void deleteMedia(final ArrayList<String> ids) {
final String blogId = String.valueOf(WordPress.getCurrentBlog().getLocalTableBlogId());
Set<String> sanitizedIds = new HashSet<>(ids.size());
// phone layout: pop the item fragment if it's visible
getFragmentManager().popBackStack();
// Make sure there are no media in "uploading"
for (String currentID : ids) {
if (WordPressMediaUtils.canDeleteMedia(blogId, currentID)) {
sanitizedIds.add(currentID);
}
}
if (sanitizedIds.size() != ids.size()) {
if (ids.size() == 1) {
Toast.makeText(this, R.string.wait_until_upload_completes, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, R.string.cannot_delete_multi_media_items, Toast.LENGTH_LONG).show();
}
}
// mark items for delete without actually deleting items yet,
// and then refresh the grid
WordPress.wpDB.setMediaFilesMarkedForDelete(blogId, sanitizedIds);
startMediaDeleteService();
if (mMediaGridFragment != null) {
mMediaGridFragment.clearSelectedItems();
mMediaGridFragment.refreshMediaFromDB();
}
}
private void showNewMediaMenu() {
View view = findViewById(R.id.menu_new_media);
if (view != null) {
int y_offset = getResources().getDimensionPixelSize(R.dimen.action_bar_spinner_y_offset);
int[] loc = new int[2];
view.getLocationOnScreen(loc);
mAddMediaPopup.showAtLocation(view, Gravity.TOP | Gravity.LEFT, loc[0],
loc[1] + view.getHeight() + y_offset);
} else {
// In case menu button is not on screen (declared showAsAction="ifRoom"), center the popup in the view.
View gridView = findViewById(R.id.media_gridview);
mAddMediaPopup.showAtLocation(gridView, Gravity.CENTER, 0, 0);
}
}
}