package org.witness.informacam.app.screens;
import info.guardianproject.iocipher.File;
import info.guardianproject.iocipher.camera.StorageManager;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import org.witness.informacam.InformaCam;
import org.witness.informacam.app.R;
import org.witness.informacam.app.RemoteShareActivity;
import org.witness.informacam.app.screens.popups.SharePopup;
import org.witness.informacam.app.utils.Constants.App.Home;
import org.witness.informacam.app.utils.Constants.HomeActivityListener;
import org.witness.informacam.app.utils.Constants.Preferences;
import org.witness.informacam.app.utils.adapters.GalleryFilterAdapter;
import org.witness.informacam.app.utils.adapters.GalleryGridAdapter;
import org.witness.informacam.json.JSONException;
import org.witness.informacam.models.media.IMedia;
import org.witness.informacam.models.notifications.INotification;
import org.witness.informacam.share.DropboxSyncManager;
import org.witness.informacam.utils.Constants.App.Storage;
import org.witness.informacam.utils.Constants.ListAdapterListener;
import org.witness.informacam.utils.Constants.Models;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.Toast;
public class GalleryFragment extends Fragment implements
OnItemClickListener, OnItemLongClickListener, ListAdapterListener,
OnItemSelectedListener {
View rootView;
GridView mediaDisplayGrid;
GalleryGridAdapter galleryGridAdapter;
RelativeLayout noMedia;
Activity a = null;
boolean isInMultiSelectMode;
ArrayList<IMedia> batch = null;
List<IMedia> listMedia = null;
private static final String LOG = Home.LOG;
private final InformaCam informaCam = InformaCam.getInstance();
private ActionMode mActionMode;
private static int mCurrentFiltering;
private MenuItem mMenuItemBatchOperations;
private View mEncodingMedia;
private MenuItem miDropbox;
@SuppressWarnings("unused")
private boolean isDataInitialized;
private ProgressBar progressWait;
private int mNumLoading;
private int mLastProgress = -1;
private Handler h = new Handler() {
@Override
public void handleMessage(Message msg) {
Bundle b = msg.getData();
/*
if(b.containsKey(Models.IMedia.VERSION)) {
if (b.getString(Models.IMedia.VERSION) != null) {
mediaExportUris.add(Uri
.fromFile(new java.io.File(b
.getString(Models.IMedia.VERSION))));
h.post(new Runnable ()
{
public void run ()
{
barProgressDialog.incrementProgressBy(1);
if (barProgressDialog.getProgress() == barProgressDialog.getMax())
{
barProgressDialog.dismiss();
showShareDialog();
}
}
});
}
} else if(b.containsKey(Codes.Keys.UI.PROGRESS)) {
}
else
*/
if (msg.what == -1)
{
String errMsg = b.getString("msg");
Toast.makeText(a,errMsg, Toast.LENGTH_LONG).show();
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater li, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(li, container, savedInstanceState);
rootView = li.inflate(R.layout.fragment_gallery, null);
mediaDisplayGrid = (GridView) rootView
.findViewById(R.id.media_display_grid);
noMedia = (RelativeLayout) rootView
.findViewById(R.id.media_display_no_media);
noMedia.setVisibility(View.GONE);
progressWait = (ProgressBar) rootView.findViewById(R.id.progressWait);
progressWait.setVisibility(View.GONE);
mEncodingMedia = rootView.findViewById(R.id.media_encoding);
mEncodingMedia.setVisibility(View.GONE);
mEncodingMedia.findViewById(R.id.ivClose).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mEncodingMedia.setVisibility(View.GONE);
}
});
return rootView;
}
@Override
public void onAttach(Activity a) {
super.onAttach(a);
this.a = a;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initLayout(savedInstanceState);
}
@Override
public void onResume()
{
super.onResume();
updateAdapters();
DropboxSyncManager.getInstance(a).finishAuthentication();
}
public void initData() {
mCurrentFiltering = 0; //All items
updateData();
}
public static List<IMedia> getMediaList()
{
int sorting = Models.IMediaManifest.Sort.DATE_DESC;
if (mCurrentFiltering == 1) // Photos
sorting = Models.IMediaManifest.Sort.TYPE_PHOTO;
else if (mCurrentFiltering == 2)
sorting = Models.IMediaManifest.Sort.TYPE_VIDEO;
List<IMedia> listSource = InformaCam.getInstance().mediaManifest.sortBy(sorting);
List<IMedia> listMedia = null;
if (listSource != null) {
listMedia = new ArrayList<IMedia>(listSource);
if (mCurrentFiltering == 3) // Tagged items
{
for (int i = listMedia.size() - 1; i >= 0; i--) {
IMedia m = listMedia.get(i);
boolean hasTags = (m.getInnerLevelRegions().size() > 0);
if (!hasTags)
listMedia.remove(i);
}
} else if (mCurrentFiltering == 4) // Shared items
{
List<INotification> listNotifications = InformaCam.getInstance().notificationsManifest.sortBy(Models.INotificationManifest.Sort.DATE_DESC);
for (int i = listMedia.size() - 1; i >= 0; i--) {
boolean hasBeenShared = false;
IMedia m = listMedia.get(i);
for (INotification n : listNotifications) {
if (m._id.equals(n.mediaId)) {
if (n.type == Models.INotification.Type.SHARED_MEDIA &&
n.taskComplete) {
hasBeenShared = true;
break;
}
}
}
if (!hasBeenShared)
listMedia.remove(i);
}
} else if (mCurrentFiltering == 5) // encrypted items
{
for (int i = listMedia.size() - 1; i >= 0; i--) {
IMedia m = listMedia.get(i);
if (m.dcimEntry.fileAsset.source != Storage.Type.IOCIPHER)
listMedia.remove(i);
}
} else if (mCurrentFiltering == 6) // unencrypted items
{
if (listMedia != null) {
for (int i = listMedia.size() - 1; i >= 0; i--) {
IMedia m = listMedia.get(i);
if (m.dcimEntry.fileAsset.source != Storage.Type.FILE_SYSTEM)
listMedia.remove(i);
}
}
}
}
return listMedia;
}
private void onMediaListAvailable()
{
//progressWait.setVisibility(View.GONE);
galleryGridAdapter = new GalleryGridAdapter(a, listMedia);
galleryGridAdapter.setNumLoading(mNumLoading);
galleryGridAdapter.setInSelectionMode(isInMultiSelectMode);
if (mediaDisplayGrid != null) {
mediaDisplayGrid.setAdapter(galleryGridAdapter);
mediaDisplayGrid.setOnItemLongClickListener(this);
mediaDisplayGrid.setOnItemClickListener(this);
}
updateAdapters();
if((listMedia != null && listMedia.size() > 0) || this.mNumLoading > 0) {
if (noMedia != null)
noMedia.setVisibility(View.GONE);
} else {
if (noMedia != null)
noMedia.setVisibility(View.VISIBLE);
}
}
private void updateData()
{
Thread getMediaListThread = new Thread(new Runnable()
{
@Override
public void run() {
listMedia = getMediaList();
if (a != null)
a.runOnUiThread(new Runnable()
{
@Override
public void run() {
onMediaListAvailable();
}
});
}
});
getMediaListThread.start();
}
public void toggleMultiSelectMode(boolean mode) {
isInMultiSelectMode = mode;
if (galleryGridAdapter != null)
galleryGridAdapter.setInSelectionMode(isInMultiSelectMode);
toggleMultiSelectMode();
}
public void toggleMultiSelectMode() {
// multiSelect.setImageDrawable(a.getResources().getDrawable(isInMultiSelectMode
// ? R.drawable.ic_action_selected : R.drawable.ic_action_select));
if (isInMultiSelectMode) {
batch = new ArrayList<IMedia>();
// batchEditHolder.setVisibility(View.VISIBLE);
} else {
batch = null;
// batchEditHolder.setVisibility(View.GONE);
}
if (galleryGridAdapter != null)
galleryGridAdapter.update(listMedia);
// galleryListAdapter.update(listMedia);
}
private void initLayout(Bundle savedInstanceState) {
mediaDisplayGrid.removeAllViewsInLayout();
toggleMultiSelectMode(false);
}
@Override
public boolean onItemLongClick(final AdapterView<?> adapterView, final View view,
final int position, final long id) {
if (position < mNumLoading)
return false; // Ignore clicks on incomplete items
mActionMode = getActivity().startActionMode(
mActionModeSelect);
h.postDelayed(new Runnable ()
{
public void run ()
{
int actualPosition = position - mNumLoading;
onItemClick(adapterView, view, actualPosition, id);
}
}
, 100);
return true;
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position,
long id) {
if (position < mNumLoading)
return; // Ignore clicks on incomplete items
position -= mNumLoading;
if (!isInMultiSelectMode) {
((HomeActivityListener) a).launchEditor(listMedia.get(position));
} else {
try {
IMedia m = listMedia.get(position);
if (!m.has(Models.IMedia.TempKeys.IS_SELECTED)) {
m.put(Models.IMedia.TempKeys.IS_SELECTED, false);
}
if (m.getBoolean(Models.IMedia.TempKeys.IS_SELECTED)) {
m.put(Models.IMedia.TempKeys.IS_SELECTED, false);
batch.remove(m);
} else {
m.put(Models.IMedia.TempKeys.IS_SELECTED, true);
batch.add(m);
}
CheckBox chkSelected = (CheckBox) view
.findViewById(R.id.chkSelect);
chkSelected.setChecked(m
.getBoolean(Models.IMedia.TempKeys.IS_SELECTED));
if (mActionMode != null)
mActionMode.invalidate();
// LinearLayout ll = (LinearLayout)
// view.findViewById(R.id.gallery_thumb_holder);
// ll.setBackgroundDrawable(getResources().getDrawable(selectedColor));
} catch (JSONException e) {
Log.e(LOG, e.toString());
e.printStackTrace();
}
}
}
private boolean mIsSelectAll = false;
private void selectAll (boolean select)
{
mIsSelectAll = select;
for (IMedia m : listMedia)
{
m.put(Models.IMedia.TempKeys.IS_SELECTED, select);
if (select)
batch.add(m);
else
batch.remove(m);
mediaDisplayGrid.invalidate();
mActionMode.invalidate();
updateAdapters();
}
}
private void updateAdapters() {
if (listMedia != null && galleryGridAdapter != null)
this.galleryGridAdapter.update(listMedia);
if ((listMedia != null && listMedia.size() > 0) || this.mNumLoading > 0)
{
if (noMedia != null)
noMedia.setVisibility(View.GONE);
if (mMenuItemBatchOperations != null)
mMenuItemBatchOperations.setVisible(true);
}
else
{
if (noMedia != null)
noMedia.setVisibility(View.VISIBLE);
if (mMenuItemBatchOperations != null)
mMenuItemBatchOperations.setVisible(false);
}
}
@Override
public void updateAdapter(int which) {
Log.d(LOG, "UPDATING OUR ADAPTERS");
if (a != null) {
updateData();
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.activity_home_gallery, menu);
MenuItem menuFilter = menu.findItem(R.id.menu_filter);
Spinner spinner = (Spinner) menuFilter.getActionView();
GalleryFilterAdapter spinnerAdapter = new GalleryFilterAdapter(spinner.getContext(), this.getResources().getTextArray(R.array.filter_options));
spinner.setAdapter(spinnerAdapter);
spinner.setOnItemSelectedListener(this);
mMenuItemBatchOperations = menu.findItem(R.id.menu_select);
miDropbox = menu.findItem(R.id.menu_remote_access_dropbox);
DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
if (dsm != null && dsm.isSyncing())
miDropbox.setChecked(true);
ActionBar actionBar = getActivity().getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(R.string.home_gallery_title);
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setHomeButtonEnabled(true);
actionBar.setLogo(this.getResources().getDrawable(
R.drawable.ic_action_up));
actionBar.setDisplayUseLogoEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
((HomeActivityListener) a).launchMain();
return true;
case R.id.menu_select:
mActionMode = getActivity().startActionMode(
mActionModeSelect);
return true;
case R.id.menu_remote_access_tor:
enableOnionShare();
return true;
case R.id.menu_remote_access_dropbox:
manageDropboxSync(!item.isChecked());
return true;
}
return super.onOptionsItemSelected(item);
}
private final ActionMode.Callback mActionModeSelect = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.activity_home_gallery_action_mode, menu);
// menu.add(Menu.NONE, R.string.menu_share, 0, R.string.menu_share)
// .setIcon(R.drawable.ic_gallery_share);
// menu.add(Menu.NONE, R.string.home_gallery_delete, 0,
// R.string.home_gallery_delete).setIcon(
// R.drawable.ic_gallery_trash);
toggleMultiSelectMode(true);
return true;
}
// Called each time the action mode is shown. Always called after
// onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
int nSelected = (batch == null) ? 0 : batch.size();
mode.setTitle(GalleryFragment.this.getString(
R.string.home_gallery_selected, nSelected));
MenuItem miDropbox2 = menu.findItem(R.id.menu_remote_access_dropbox);
DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
if (dsm != null && dsm.isSyncing())
miDropbox2.setChecked(true);
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
int shareType = SharePopup.SHARE_TYPE_MEDIA;
boolean isLocalShare = PreferenceManager.getDefaultSharedPreferences(a).getBoolean("prefExportLocal", false);
switch (item.getItemId()) {
case R.string.menu_done:
mode.finish(); // Action picked, so close the CAB
return true;
case R.id.menu_home_gallery_select_all:
selectAll(!mIsSelectAll);
return true;
case R.id.menu_share_hash:
shareHashes();
return true;
case R.id.menu_remote_access_tor:
enableOnionShare();
return true;
case R.id.menu_remote_access_dropbox:
manageDropboxSync(!item.isChecked());
return true;
case R.id.menu_share_meta_j3m:
shareType = SharePopup.SHARE_TYPE_J3M;
case R.id.menu_share_meta_csv:
shareType = SharePopup.SHARE_TYPE_CSV;
case R.id.menu_share:
if (batch.size() > 0)
{
new SharePopup(a,batch,false,shareType,isLocalShare);
}
else
{
batch.clear();
mode.finish();
}
return true;
case R.id.menu_home_gallery_delete:
((HomeActivityListener) a).waiter(true);
new Thread(new Runnable() {
private ActionMode mMode;
@Override
public void run() {
for (IMedia m : batch) {
m.delete();
}
h.post(new Runnable() {
private ActionMode mMode;
@Override
public void run() {
mMode.finish();
((HomeActivityListener) a).waiter(false);
updateData();
}
public Runnable init(ActionMode mode) {
mMode = mode;
return this;
}
}.init(mMode));
}
public Runnable init(ActionMode mode) {
mMode = mode;
return this;
}
}.init(mode)).start();
return true;
default:
return false;
}
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
toggleMultiSelectMode(false);
DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
if (dsm != null && dsm.isSyncing())
miDropbox.setChecked(true);
else
miDropbox.setChecked(false);
}
};
private void shareHashes ()
{
try
{
StringBuffer hexStrings = new StringBuffer();
for (IMedia media : batch)
{
String mediaId = ((IMedia) media)._id;
boolean hasBeenShared = false;
List<INotification> listNotifs = InformaCam.getInstance().notificationsManifest.sortBy(Models.INotificationManifest.Sort.DATE_DESC);
for (INotification n :listNotifs)
{
if (mediaId.equals(n.mediaId))
{
//this means we sent to an organization, likely the testbed
if ((n.type == Models.INotification.Type.EXPORTED_MEDIA) &&
n.taskComplete)
{
hasBeenShared = true;
}
}
}
@SuppressWarnings("unused")
String j3m = ((IMedia) media).buildJ3M(a, false, null);
//generate public hash id from values
String creatorHash = media.genealogy.createdOnDevice;
StringBuffer mediaHash = new StringBuffer();
for(String mHash : media.genealogy.hashes) {
mediaHash.append(mHash);
}
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-1");
md.update((creatorHash+mediaHash.toString()).getBytes());
byte[] byteData = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
hexStrings.append(getString(R.string._id_)).append(hexString).append(' ');
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
//if (!hasBeenShared) //if it hasn't been shared, then just show the hashes
sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string._camerav_notarization_id_) + ' ' + hexStrings.toString().trim());
//else //if it has, then show a URL
//sendIntent.putExtra(Intent.EXTRA_TEXT, "#" + getString(R.string.app_name) + " https://j3m.info/submissions/?hashes=" + hexString + " (media:" + mediaHash + ")");
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
catch (Exception e)
{
}
}
@Override
public void setPending(final int numPending, final int numCompleted) {
if(a == null) {
return;
}
mNumLoading = numPending - numCompleted;
a.runOnUiThread(new Runnable() {
@Override
public void run() {
if (galleryGridAdapter != null)
{
galleryGridAdapter.setNumLoading(numPending - numCompleted);
}
if (numPending > 0 && numCompleted == 0)
{
SharedPreferences sp = a.getSharedPreferences(a.getResources().getString(R.string.app_name), Context.MODE_PRIVATE);
int nTimesShown = sp.getInt(Preferences.Keys.HINT_PROCESSING_IMAGES_SHOWN, 0);
if (nTimesShown < 3)
{
nTimesShown++;
sp.edit().putInt(Preferences.Keys.HINT_PROCESSING_IMAGES_SHOWN, nTimesShown).commit();
mEncodingMedia.setVisibility(View.VISIBLE);
}
}
else if (mNumLoading == 0)
{
mEncodingMedia.setVisibility(View.GONE);
}
}
});
}
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int itemPosition,
long itemId) {
mCurrentFiltering = itemPosition;
updateAdapter(0);
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
private void enableOnionShare ()
{
Intent intent = new Intent(a, RemoteShareActivity.class);
if (batch != null && batch.size() > 0)
{
ArrayList<String> mediaIds = new ArrayList<String>();
for (IMedia media : batch)
mediaIds.add(media._id);
intent.putExtra("medialist", mediaIds.toArray(new String[mediaIds.size()]));
}
startActivity(intent);
}
private void manageDropboxSync (boolean enable)
{
miDropbox.setChecked(enable);
DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
if (enable)
{
if (!dsm.isSyncing())
{
//do web oauth (doesn't require local app)
boolean isInit = dsm.start(a);
if (isInit) //if init'd, then backup all existing files that aren't already backed up!
{
if (batch != null)
for (IMedia media : batch)
{
dsm.uploadMediaAsync(media);
}
}
}
}
else
{
dsm.stop();
}
}
}