gt:                     + " - " + event.error.message);
context: package org.wordpress.android.ui.media;
  
  import android.annotation.SuppressLint;
  import android.app.Activity;
  import android.app.AlertDialog;
  import android.app.Fragment;
  import android.app.FragmentManager;
  import android.app.FragmentManager.OnBackStackChangedListener;
  import android.app.FragmentTransaction;
  import android.content.BroadcastReceiver;
  import android.content.ComponentName;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.ServiceConnection;
  import android.content.pm.PackageManager;
  import android.graphics.drawable.ColorDrawable;
  import android.net.ConnectivityManager;
  import android.net.Uri;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.os.IBinder;
  import android.support.annotation.NonNull;
  import android.support.annotation.Nullable;
  import android.support.annotation.StringRes;
  import android.support.v4.view.MenuItemCompat;
  import android.support.v4.view.MenuItemCompat.OnActionExpandListener;
  import android.support.v7.app.ActionBar;
  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.webkit.MimeTypeMap;
  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.greenrobot.eventbus.Subscribe;
  import org.greenrobot.eventbus.ThreadMode;
  import org.wordpress.android.BuildConfig;
  import org.wordpress.android.R;
  import org.wordpress.android.WordPress;
  import org.wordpress.android.analytics.AnalyticsTracker;
  import org.wordpress.android.fluxc.Dispatcher;
  import org.wordpress.android.fluxc.generated.MediaActionBuilder;
  import org.wordpress.android.fluxc.model.MediaModel;
  import org.wordpress.android.fluxc.model.SiteModel;
  import org.wordpress.android.fluxc.store.MediaStore;
  import org.wordpress.android.fluxc.store.MediaStore.OnMediaChanged;
  import org.wordpress.android.fluxc.store.MediaStore.OnMediaListFetched;
  import org.wordpress.android.fluxc.store.MediaStore.OnMediaUploaded;
  import org.wordpress.android.models.MediaUploadState;
  import org.wordpress.android.ui.ActivityId;
  import org.wordpress.android.ui.RequestCodes;
  import org.wordpress.android.ui.media.MediaEditFragment.MediaEditFragmentCallback;
  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.MediaUploadService;
  import org.wordpress.android.util.ActivityUtils;
  import org.wordpress.android.util.AnalyticsUtils;
  import org.wordpress.android.util.AppLog;
  import org.wordpress.android.util.DateTimeUtils;
  import org.wordpress.android.util.MediaUtils;
  import org.wordpress.android.util.NetworkUtils;
  import org.wordpress.android.util.PermissionUtils;
  import org.wordpress.android.util.ToastUtils;
  import org.wordpress.android.util.WPActivityUtils;
  import org.wordpress.android.util.WPMediaUtils;
  import org.wordpress.passcodelock.AppLockManager;
  
  import java.io.File;
  import java.util.ArrayList;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import javax.inject.Inject;
  
  /**
   * The main activity in which the user can browse their media.
   */
  public class MediaBrowserActivity extends AppCompatActivity implements MediaGridListener,
          MediaItemFragmentCallback, OnQueryTextListener, OnActionExpandListener,
          MediaEditFragmentCallback, WordPressMediaUtils.LaunchCameraCallback {
      private static final int MEDIA_PERMISSION_REQUEST_CODE = 1;
  
      private static final String SAVED_QUERY = "SAVED_QUERY";
      private static final String BUNDLE_MEDIA_CAPTURE_PATH = "mediaCapturePath";
  
      @Inject Dispatcher mDispatcher;
      @Inject MediaStore mMediaStore;
  
      private SiteModel mSite;
  
      private MediaGridFragment mMediaGridFragment;
      private MediaItemFragment mMediaItemFragment;
      private MediaEditFragment mMediaEditFragment;
      private PopupWindow mAddMediaPopup;
  
      // Views
      private Toolbar mToolbar;
      private SearchView mSearchView;
      private MenuItem mSearchMenuItem;
      private Menu mMenu;
  
      // Services
      private MediaDeleteService.MediaDeleteBinder mDeleteService;
      private boolean mDeleteServiceBound;
  
      private String mQuery;
      private String mMediaCapturePath;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  
          ((WordPress) getApplication()).component().inject(this);
  
          if (savedInstanceState == null) {
              mSite = (SiteModel) getIntent().getSerializableExtra(WordPress.SITE);
          } else {
              mSite = (SiteModel) savedInstanceState.getSerializable(WordPress.SITE);
          }
  
          if (mSite == null) {
              ToastUtils.showToast(this, R.string.blog_not_found, ToastUtils.Duration.SHORT);
              finish();
              return;
          }
  
          setContentView(R.layout.media_browser_activity);
  
          mToolbar = (Toolbar) findViewById(R.id.toolbar);
          setSupportActionBar(mToolbar);
          ActionBar actionBar = getSupportActionBar();
          if (actionBar != null) {
              actionBar.setDisplayShowTitleEnabled(true);
              actionBar.setDisplayHomeAsUpEnabled(true);
              actionBar.setTitle(R.string.media);
          }
  
          FragmentManager fm = getFragmentManager();
          fm.addOnBackStackChangedListener(mOnBackStackChangedListener);
  
          mMediaGridFragment = (MediaGridFragment) fm.findFragmentById(R.id.mediaGridFragment);
          mMediaItemFragment = (MediaItemFragment) fm.findFragmentByTag(MediaItemFragment.TAG);
          mMediaEditFragment = (MediaEditFragment) fm.findFragmentByTag(MediaEditFragment.TAG);
  
          FragmentTransaction ft = fm.beginTransaction();
          if (mMediaItemFragment != null) {
              ft.hide(mMediaGridFragment);
          }
          if (mMediaEditFragment != null && !mMediaEditFragment.isInLayout()) {
              ft.hide(mMediaItemFragment);
          }
          ft.commitAllowingStateLoss();
  
          setupAddMenuPopup();
  
          // if media was shared add it to the library
          handleSharedMedia();
      }
  
      @Override
      public void onStart() {
          super.onStart();
          registerReceiver(mReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
          mDispatcher.register(this);
      }
  
      @Override
      protected void onPause() {
          super.onPause();
  
          if (mSearchMenuItem != null) {
              String tempQuery = mQuery;
              MenuItemCompat.collapseActionView(mSearchMenuItem);
              mQuery = tempQuery;
          }
      }
  
      @Override
      public void onPause(Fragment fragment) {
          invalidateOptionsMenu();
      }
  
      @Override
      protected void onResume() {
          super.onResume();
          startMediaDeleteService(null);
          ActivityId.trackLastActivity(ActivityId.MEDIA);
      }
  
      @Override
      public void onResume(Fragment fragment) {
          invalidateOptionsMenu();
      }
  
      @Override
      public void onStop() {
          unregisterReceiver(mReceiver);
          mDispatcher.unregister(this);
          super.onStop();
      }
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
          doUnbindDeleteService();
      }
  
      @Override
      protected void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
  
          outState.putString(SAVED_QUERY, mQuery);
          outState.putSerializable(WordPress.SITE, mSite);
          if (!TextUtils.isEmpty(mMediaCapturePath)) {
              outState.putString(BUNDLE_MEDIA_CAPTURE_PATH, mMediaCapturePath);
          }
      }
  
      @Override
      protected void onRestoreInstanceState(Bundle savedInstanceState) {
          super.onRestoreInstanceState(savedInstanceState);
  
          mSite = (SiteModel) savedInstanceState.getSerializable(WordPress.SITE);
          mMediaCapturePath = savedInstanceState.getString(BUNDLE_MEDIA_CAPTURE_PATH);
          mQuery = savedInstanceState.getString(SAVED_QUERY);
      }
  
      @Override
      public void onBackPressed() {
          FragmentManager fm = getFragmentManager();
          if (fm.getBackStackEntryCount() > 0) {
              if (mMediaEditFragment != null && mMediaEditFragment.isVisible() && mMediaEditFragment.isDirty()) {
                  // alert the user that there are unsaved changes
                  new AlertDialog.Builder(this)
                          .setMessage(R.string.confirm_discard_changes)
                          .setCancelable(true)
                          .setPositiveButton(R.string.discard, new DialogInterface.OnClickListener() {
                              @Override
                              public void onClick(DialogInterface dialog, int which) {
                                  // make sure the keyboard is dismissed
                                  WPActivityUtils.hideKeyboard(getCurrentFocus());
  
                                  // pop the edit fragment
                                  doPopBackStack(getFragmentManager());
                              }})
                          .setNegativeButton(R.string.cancel, null)
                          .create()
                          .show();
              } else {
                  doPopBackStack(fm);
              }
          } else {
              super.onBackPressed();
          }
      }
  
      @Override
      public void onActivityResult(int requestCode, int resultCode, Intent data) {
          super.onActivityResult(requestCode, resultCode, data);
  
          switch (requestCode) {
              case RequestCodes.PICTURE_LIBRARY:
              case RequestCodes.VIDEO_LIBRARY:
                  if (resultCode == Activity.RESULT_OK && data != null) {
                      Uri imageUri = data.getData();
                      String mimeType = getContentResolver().getType(imageUri);
                      fetchMedia(imageUri, mimeType);
                      trackAddMediaFromDeviceEvents(
                              false,
                              requestCode == RequestCodes.VIDEO_LIBRARY,
                              imageUri
                      );
                  }
                  break;
              case RequestCodes.TAKE_PHOTO:
                  if (resultCode == Activity.RESULT_OK) {
                      Uri uri;
                      Uri optimizedMedia = WPMediaUtils.getOptimizedMedia(this, mSite, mMediaCapturePath, false);
                      if (optimizedMedia != null) {
                          uri = optimizedMedia;
                      } else {
                          uri = Uri.parse(mMediaCapturePath);
                      }
                      mMediaCapturePath = null;
                      queueFileForUpload(uri, getContentResolver().getType(uri));
                      trackAddMediaFromDeviceEvents(true, false, uri);
                  }
                  break;
              case RequestCodes.TAKE_VIDEO:
                  if (resultCode == Activity.RESULT_OK) {
                      Uri uri = MediaUtils.getLastRecordedVideoUri(this);
                      queueFileForUpload(uri, getContentResolver().getType(uri));
                      trackAddMediaFromDeviceEvents(true, true, uri);
                  }
                  break;
          }
      }
  
      /**
       * Analytics about new media
       *
       * @param isNewMedia Whether is a fresh (just taken) photo/video or not
       * @param isVideo Whether is a video or not
       * @param uri The URI of the media on the device, or null
       */
      private void trackAddMediaFromDeviceEvents(boolean isNewMedia, boolean isVideo, Uri uri) {
          if (uri == null) {
              AppLog.e(AppLog.T.MEDIA, "Cannot track new media event if mediaURI is null!!");
              return;
          }
  
          Map<String, Object> properties = AnalyticsUtils.getMediaProperties(this, isVideo, uri, null);
          properties.put("via", isNewMedia ? "device_camera" : "device_library");
  
          if (isVideo) {
              AnalyticsTracker.track(AnalyticsTracker.Stat.MEDIA_LIBRARY_ADDED_VIDEO, properties);
          } else {
              AnalyticsTracker.track(AnalyticsTracker.Stat.MEDIA_LIBRARY_ADDED_PHOTO, properties);
          }
      }
  
      @Override
      public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] results) {
          // only MEDIA_PERMISSION_REQUEST_CODE is handled
          if (requestCode != MEDIA_PERMISSION_REQUEST_CODE) {
              return;
          }
  
          for (int grantResult : results) {
              if (grantResult == PackageManager.PERMISSION_DENIED) {
                  ToastUtils.showToast(this, getString(R.string.add_media_permission_required));
                  return;
              }
          }
  
          showNewMediaMenu();
      }
  
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          mMenu = menu;
          getMenuInflater().inflate(R.menu.media_browser, menu);
  
          mSearchMenuItem = menu.findItem(R.id.menu_search);
          MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, this);
  
          mSearchView = (SearchView) mSearchMenuItem.getActionView();
          mSearchView.setOnQueryTextListener(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.onCreateOptionsMenu(menu);
      }
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          switch (item.getItemId()) {
              case android.R.id.home:
                  onBackPressed();
                  return true;
              case R.id.menu_new_media:
                  AppLockManager.getInstance().setExtendedTimeout();
                  if (PermissionUtils.checkAndRequestCameraAndStoragePermissions(this, MEDIA_PERMISSION_REQUEST_CODE)) {
                      showNewMediaMenu();
                  }
                  return true;
              case 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;
              case R.id.menu_edit_media:
                  int localMediaId = mMediaItemFragment.getLocalMediaId();
  
                  if (mMediaEditFragment == null || !mMediaEditFragment.isInLayout()) {
                      // phone layout: hide item details, show and update edit fragment
                      FragmentManager fm = getFragmentManager();
                      mMediaEditFragment = MediaEditFragment.newInstance(mSite, localMediaId);
  
                      FragmentTransaction ft = fm.beginTransaction();
                      if (mMediaItemFragment.isVisible()) {
                          ft.hide(mMediaItemFragment);
                      }
                      ft.add(R.id.media_browser_container, mMediaEditFragment, MediaEditFragment.TAG);
                      ft.addToBackStack(null);
                      ft.commitAllowingStateLoss();
                  } else {
                      // tablet layout: update edit fragment
                      mMediaEditFragment.loadMedia(localMediaId);
                  }
  
                  if (mSearchView != null) {
                      mSearchView.clearFocus();
                  }
  
                  return true;
          }
  
          return super.onOptionsItemSelected(item);
      }
  
      @Override
      public boolean onMenuItemActionExpand(MenuItem item) {
          if (mMediaGridFragment != null) {
              mMediaGridFragment.setFilterEnabled(false);
          }
  
          // 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.setFilterEnabled(true);
          }
  
          mMenu.findItem(R.id.menu_new_media).setVisible(true);
          invalidateOptionsMenu();
  
          return 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 setLookClosable() {
          mToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp);
      }
  
      @Override
      public void onMediaItemSelected(int localMediaId) {
          final String tempQuery = mQuery;
  
          if (mSearchView != null) {
              mSearchView.clearFocus();
          }
  
          if (mSearchMenuItem != null) {
              MenuItemCompat.collapseActionView(mSearchMenuItem);
          }
  
          FragmentManager fm = getFragmentManager();
          if (fm.getBackStackEntryCount() == 0) {
              mMediaGridFragment.clearSelectedItems();
              mMediaItemFragment = MediaItemFragment.newInstance(mSite, localMediaId);
  
              FragmentTransaction ft = fm.beginTransaction();
              ft.hide(mMediaGridFragment);
              ft.add(R.id.media_browser_container, mMediaItemFragment, MediaItemFragment.TAG);
              ft.addToBackStack(null);
              ft.commitAllowingStateLoss();
  
              mQuery = tempQuery;
          }
      }
  
      @Override
      public void onMediaCapturePathReady(String mediaCapturePath) {
          mMediaCapturePath = mediaCapturePath;
      }
  
      @Override
      public void onRetryUpload(int localMediaId) {
          MediaModel media = mMediaStore.getMediaWithLocalId(localMediaId);
          if (media == null) {
              return;
          }
          addMediaToUploadService(media);
      }
  
      private void showMediaToastError(@StringRes int message, @Nullable String messageDetail) {
          if (isFinishing()) {
              return;
          }
          String errorMessage = getString(message);
          if (!TextUtils.isEmpty(messageDetail)) {
              errorMessage += ". " + messageDetail;
          }
          ToastUtils.showToast(this, errorMessage, ToastUtils.Duration.LONG);
      }
  
      @SuppressWarnings("unused")
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void onMediaChanged(OnMediaChanged event) {
          if (event.isError()) {
              AppLog.w(AppLog.T.MEDIA, "Received onMediaChanged error: " + event.error.type
  