/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.doplgangr.secrecy.fragments;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.InputType;
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.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewAnimator;
import com.doplgangr.secrecy.Config;
import com.doplgangr.secrecy.CustomApp;
import com.doplgangr.secrecy.activities.FilePhotoActivity;
import com.doplgangr.secrecy.activities.FilesActivity;
import com.doplgangr.secrecy.events.AddingFileDoneEvent;
import com.doplgangr.secrecy.events.AddingFileEvent;
import com.doplgangr.secrecy.events.BackUpDoneEvent;
import com.doplgangr.secrecy.events.DecryptingFileDoneEvent;
import com.doplgangr.secrecy.events.NewFileEvent;
import com.doplgangr.secrecy.exceptions.SecrecyCipherStreamException;
import com.doplgangr.secrecy.filesystem.encryption.Vault;
import com.doplgangr.secrecy.filesystem.files.EncryptedFile;
import com.doplgangr.secrecy.filesystem.Storage;
import com.doplgangr.secrecy.jobs.BackupJob;
import com.doplgangr.secrecy.jobs.InitializeVaultJob;
import com.doplgangr.secrecy.R;
import com.doplgangr.secrecy.utils.Util;
import com.doplgangr.secrecy.adapters.FilesListAdapter;
import com.ipaulpro.afilechooser.FileChooserActivity;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import de.greenrobot.event.EventBus;
public class FilesListFragment extends FileViewer {
private static final int REQUEST_CODE = 6384;
private static final ArrayList<String> INCLUDE_EXTENSIONS_LIST = new ArrayList<>();
private static final int NotificationID = 1820;
private RecyclerView recyclerView;
private ProgressBar addFilepBar;
private TextView mTag;
private String vault;
private String password;
private Vault secret;
private FilesListAdapter mAdapter;
private FilesListAdapter listAdapter;
private FilesListAdapter galleryAdapter;
private int decryptCounter = 0;
private boolean isGallery = false;
private boolean attached = false;
//Notifications
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
private ProgressDialog mInitializeDialog;
private RecyclerView.LayoutManager linearLayout;
private RecyclerView.LayoutManager gridLayout;
private ActionMode mActionMode;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_file, container, false);
addFilepBar = (ProgressBar) view.findViewById(R.id.progressBar);
recyclerView = (RecyclerView) view.findViewById(R.id.file_list_recycler_view);
mTag = (TextView) view.findViewById(R.id.tag);
linearLayout = new LinearLayoutManager(context);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayout);
recyclerView.setAdapter(mAdapter);
ActionBar ab = ((ActionBarActivity) getActivity()).getSupportActionBar();
if (ab != null) {
ab.setTitle(vault);
}
return view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
Bundle extras = getActivity().getIntent().getExtras();
vault = extras.getString(Config.vault_extra);
password = extras.getString(Config.password_extra);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
setRetainInstance(true);
context = (ActionBarActivity) getActivity();
if (context == null) {
return;
}
context.getSupportActionBar().setTitle(vault);
gridLayout = new GridLayoutManager(context, 3);
listAdapter = new FilesListAdapter(context, false);
galleryAdapter = new FilesListAdapter(context, true);
mAdapter = listAdapter;
if (secret == null) {
mInitializeDialog = new ProgressDialog(context);
mInitializeDialog.setIndeterminate(true);
mInitializeDialog.setMessage(context.getString(R.string.Vault__initializing));
mInitializeDialog.setCancelable(false);
mInitializeDialog.show();
CustomApp.jobManager.addJobInBackground(new InitializeVaultJob(vault, password));
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.filelist, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem item = menu.findItem(R.id.action_switch_interface);
item.setIcon(isGallery ? R.drawable.ic_list : R.drawable.ic_gallery);
}
private final ActionMode.Callback mActionModeCallback = 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.file_action, menu);
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) {
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) {
switch (item.getItemId()) {
case R.id.action_send:
sendRawSelectedItems();
mode.finish();
return true;
case R.id.action_decrypt:
decryptSelectedItems();
mode.finish();
return true;
case R.id.action_delete:
deleteSelectedItems();
mode.finish();
return true;
case R.id.action_rename:
renameSelectedItems();
mode.finish();
return true;
case R.id.action_select_all:
selectAll();
return true;
default:
return false;
}
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
mAdapter.clearSelected();
}
};
void switchView(final View frame, final int showView) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (frame == null) {
return;
}
FilesListAdapter.ViewHolder holder = (FilesListAdapter.ViewHolder) frame.getTag();
ViewAnimator viewAnimator = holder.animator;
int viewIndex = 0;
switch (showView) {
case R.id.dataLayout:
viewIndex = 0;
break;
case R.id.DecryptLayout:
viewIndex = 1;
break;
}
viewAnimator.setDisplayedChild(viewIndex);
viewAnimator.setInAnimation(null);
holder.page = viewIndex;
}
});
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
attached = true;
}
@Override
public void onDetach() {
super.onDetach();
attached = false;
}
@Override
public void onDestroyView() {
super.onDestroyView();
EventBus.getDefault().unregister(mAdapter);
EventBus.getDefault().unregister(listAdapter);
EventBus.getDefault().unregister(galleryAdapter);
EventBus.getDefault().unregister(this);
}
void addFiles() {
new Thread(new Runnable() {
@Override
public void run() {
secret.iterateAllFiles(
new Vault.onFileFoundListener() {
@Override
public void dothis(EncryptedFile encryptedFile) {
addToList(encryptedFile);
}
});
}
}).start();
}
void updateVaultInBackground(final ProgressDialog progress) {
new Thread(new Runnable() {
@Override
public void run() {
try {
if (secret.updateFromECBVault(password)) {
Util.alert(
context,
getString(R.string.Vault__vault_updated),
getString(R.string.Vault__vault_updated_message),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
finish();
}
},
null
);
} else {
secret.ecbUpdateFailed();
Util.alert(
context,
getString(R.string.Error__updating_vault),
getString(R.string.Error__updating_vault_message),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
finish();
}
},
null
);
}
} catch (Exception e) {
secret.ecbUpdateFailed();
Util.alert(
context,
getString(R.string.Error__updating_vault),
getString(R.string.Error__updating_vault_message),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
finish();
}
},
null
);
}
progress.dismiss();
}
}).start();
}
void setupViews() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
context.supportInvalidateOptionsMenu();
FilesListAdapter.OnItemClickListener onItemClickListener = new FilesListAdapter.OnItemClickListener() {
@Override
public void onItemClick(final View view, int position) {
if (mActionMode != null) {
select(position);
return;
}
if (isGallery) {
Intent intent = new Intent(context, FilePhotoActivity.class);
intent.putExtra(Config.gallery_item_extra, position);
FilesActivity.onPauseDecision.startActivity();
startActivity(intent);
} else {
EncryptedFile encryptedFile = mAdapter.getItem(position);
if (!encryptedFile.getIsDecrypting()) {
switchView(view, R.id.DecryptLayout);
Runnable onFinish = new Runnable() {
@Override
public void run() {
switchView(view, R.id.dataLayout);
}
};
decrypt(encryptedFile, onFinish);
} else
Util.toast(context, getString(R.string.Error__already_decrypting), Toast.LENGTH_SHORT);
}
}
};
FilesListAdapter.OnItemLongClickListener onItemLongClickListener = new FilesListAdapter.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(View view, int position) {
if (mActionMode == null)
mActionMode = context.startSupportActionMode(mActionModeCallback);
// Start the CAB using the ActionMode.Callback defined above
select(position);
//switchView(view, R.id.file_actions_layout);
//mListView.setOnClickListener(null);
return true;
}
};
listAdapter.setOnItemClickListener(onItemClickListener);
listAdapter.setOnLongClickListener(onItemLongClickListener);
galleryAdapter.setOnItemClickListener(onItemClickListener);
galleryAdapter.setOnLongClickListener(onItemLongClickListener);
}
});
}
void addToList(final EncryptedFile encryptedFile) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
listAdapter.add(encryptedFile);
galleryAdapter.add(encryptedFile);
listAdapter.sort();
galleryAdapter.sort();
mAdapter.notifyDataSetChanged();
}
});
}
@Override
void decrypt(final EncryptedFile encryptedFile, final Runnable onFinish) {
super.decrypt(encryptedFile, onFinish);
}
void decrypt_and_save(final int index, final Runnable onFinish) {
new Thread(new Runnable() {
@Override
public void run() {
EncryptedFile encryptedFile = mAdapter.getItem(index);
File tempFile = getFile(encryptedFile, onFinish);
File storedFile = new File(Environment.getExternalStorageDirectory(), encryptedFile.getDecryptedFileName());
if (tempFile == null) {
Util.alert(context,
CustomApp.context.getString(R.string.Error__decrypting_file),
CustomApp.context.getString(R.string.Error__decrypting_file_message),
Util.emptyClickListener,
null
);
return;
}
tempFile.renameTo(storedFile);
}
}).start();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.action_delete_vault:
deleteVault();
return true;
case R.id.action_change_passphrase:
changePassphrase();
return true;
case R.id.action_switch_interface:
switchInterface();
return true;
case R.id.action_backup:
backUp();
return true;
case R.id.action_add_file:
addFile();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
void switchInterface() {
isGallery = !isGallery;
mTag.setText(isGallery ? R.string.Page_header__gallery : R.string.Page_header__files);
if (isGallery) {
mAdapter = galleryAdapter;
recyclerView.setLayoutManager(gridLayout);
} else {
mAdapter = listAdapter;
mAdapter.sort();
recyclerView.setLayoutManager(linearLayout);
}
recyclerView.setAdapter(mAdapter);
}
void changePassphrase() {
final View dialogView = View.inflate(context, R.layout.change_passphrase, null);
new AlertDialog.Builder(context)
.setTitle(getString(R.string.Vault__change_password))
.setView(dialogView)
.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String oldPassphrase = ((EditText) dialogView.findViewById(R.id.oldPassphrase)).getText().toString();
String newPassphrase = ((EditText) dialogView.findViewById(R.id.newPassphrase)).getText().toString();
String confirmNewPassphrase = ((EditText) dialogView.findViewById(R.id.confirmPassphrase)).getText().toString();
ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setMessage(CustomApp.context.getString(R.string.Vault__changing_password));
progressDialog.setIndeterminate(true);
progressDialog.setCancelable(false);
progressDialog.show();
changePassphraseInBackground(oldPassphrase, newPassphrase, confirmNewPassphrase, progressDialog);
}
})
.setNegativeButton(R.string.CANCEL, Util.emptyClickListener)
.show();
}
void deleteVault() {
final EditText passwordView = new EditText(context);
passwordView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
passwordView.setHint(R.string.Vault__confirm_password_hint);
new AlertDialog.Builder(context)
.setTitle(getString(R.string.Vault__confirm_delete))
.setView(passwordView)
.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String input = passwordView.getText().toString();
if (password.equals(input)) {
secret.delete();
context.finish();
} else {
Util.alert(context,
CustomApp.context.getString(R.string.Error__delete_password_incorrect),
CustomApp.context.getString(R.string.Error__delete_password_incorrect_message),
Util.emptyClickListener,
null
);
}
}
})
.setNegativeButton(R.string.CANCEL, Util.emptyClickListener)
.show();
}
void addFile() {
// Use the GET_CONTENT intent from the utility class
Intent target = com.ipaulpro.afilechooser.utils.FileUtils.createGetContentIntent();
// Create the chooser Intent
Intent intent = Intent.createChooser(
target, getString(R.string.Dialog_header__pick_file));
try {
startActivityForResult(intent, REQUEST_CODE);
FilesActivity.onPauseDecision.startActivity();
} catch (ActivityNotFoundException e) {
intent = new Intent(context, FileChooserActivity.class);
intent.putStringArrayListExtra(
FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS,
INCLUDE_EXTENSIONS_LIST);
intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, false);
startActivityForResult(intent, REQUEST_CODE);
FilesActivity.onPauseDecision.startActivity();
}
}
void backUp() {
mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle(CustomApp.context.getString(R.string.Backup__title))
.setContentText(CustomApp.context.getString(R.string.Backup__in_progress))
.setSmallIcon(R.drawable.ic_stat_alert)
.setOngoing(true);
mBuilder.setProgress(0, 0, true);
mNotifyManager.notify(NotificationID, mBuilder.build());
File backupFile = new File(Storage.getRoot(), secret.getName() + new Date().getTime() + ".zip");
try {
backupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
CustomApp.jobManager.addJobInBackground(new BackupJob(context, new File(secret.getPath()), backupFile));
}
void changePassphraseInBackground(final String oldPassphrase, final String newPassphrase,
final String confirmNewPassphrase, final ProgressDialog progressDialog) {
new Thread(new Runnable() {
public void run() {
if (newPassphrase.length() == 0) {
progressDialog.dismiss();
Util.alert(context,
CustomApp.context.getString(R.string.Error__change_password_failed),
CustomApp.context.getString(R.string.Error__password_empty_message),
Util.emptyClickListener,
null
);
return;
}
if (!newPassphrase.equals(confirmNewPassphrase)) {
progressDialog.dismiss();
Util.alert(context,
CustomApp.context.getString(R.string.Error__change_password_failed),
CustomApp.context.getString(R.string.Error__password_no_match_message),
Util.emptyClickListener,
null
);
return;
}
if (!secret.changePassphrase(oldPassphrase, newPassphrase)) {
progressDialog.dismiss();
Util.alert(context,
CustomApp.context.getString(R.string.Error__change_password_failed),
CustomApp.context.getString(R.string.Error__change_password_failed_message),
Util.emptyClickListener,
null
);
} else {
Util.alert(context,
CustomApp.context.getString(R.string.Vault__change_password_ok),
CustomApp.context.getString(R.string.Vault__change_password_ok_message),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
context.finish();
}
}
);
}
progressDialog.dismiss();
}
}).start();
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
FilesActivity.onPauseDecision.finishActivity();
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE && data.getData() != null) {
Util.log("intent received=", data.getData().toString(), data.getData().getLastPathSegment());
mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle(CustomApp.context.getString(R.string.Files__adding))
.setSmallIcon(R.drawable.ic_stat_alert)
.setOngoing(true);
mBuilder.setProgress(0, 0, true);
mNotifyManager.notify(NotificationID, mBuilder.build());
addFileInBackground(secret, data.getData());
super.onActivityResult(requestCode, resultCode, data);
} else {
Util.toast(context, getString(R.string.Error__no_file_selected), 4000);
}
}
public void onEventMainThread(NewFileEvent event) {
// Add new file to the list, sort it to its alphabetical position, and highlight
// it with smooth scrolling.
if ((mAdapter != null) && (attached)) {
Util.toast(context,
CustomApp.context.getString(R.string.Files__add_successful),
Toast.LENGTH_SHORT);
addToList(event.encryptedFile);
mAdapter.sort();
int index = mAdapter.getItemId(event.encryptedFile);
if (index != -1)
recyclerView.smoothScrollToPosition(index);
}
}
public void onEventMainThread(Vault vault) {
//The vault finishes initializing, is prepared to be populated.
secret = vault;
if (secret.isEcbVault()) {
Util.alert(
context,
getString(R.string.Error__old_vault_format),
getString(R.string.Error__old_vault_format_message),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Util.alert(
context,
getString(R.string.Upgrade__backup_beforehand),
getString(R.string.Upgrade__backup_beforehand_message),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
backUp();
finish();
}
},
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ProgressDialog progress = new ProgressDialog(context);
progress.setMessage(getString(R.string.Vault_updating));
progress.setIndeterminate(true);
progress.setCancelable(false);
progress.show();
updateVaultInBackground(progress);
}
}
);
}
},
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
finish();
}
}
);
return;
}
if (secret.wrongPass) {
Util.alert(
context,
getString(R.string.Error__open_vault),
getString(R.string.Error__open_vault_message),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
finish();
}
},
null
);
return;
}
addFiles();
context.setTitle(secret.getName());
mInitializeDialog.dismiss();
setupViews();
}
public void onEventMainThread(BackUpDoneEvent event) {
if (!event.backupPath.getAbsolutePath().equals(secret.getPath()))
return;
if (mBuilder != null) {
mBuilder.setProgress(0, 0, false)
.setContentText(String.format(CustomApp.context.getString(R.string.Backup__finish), event.backupFile))
.setStyle(new NotificationCompat.BigTextStyle().bigText( //For long long text
String.format(CustomApp.context.getString(R.string.Backup__finish), event.backupFile)))
.setOngoing(false);
mNotifyManager.notify(NotificationID, mBuilder.build());
}
}
public void onEventMainThread(AddingFileEvent event) {
if (event.vaultToAdd != secret)
return;
if (mBuilder != null) {
mBuilder.setContentText(event.fileToAdd);
mNotifyManager.notify(NotificationID, mBuilder.build());
}
}
public void onEventMainThread(AddingFileDoneEvent event) {
if (event.vault != secret)
return;
if (mBuilder != null) {
mBuilder.setProgress(0, 0, false)
.setContentText(CustomApp.context.getString(R.string.Files__adding_finish))
.setOngoing(false);
mNotifyManager.notify(NotificationID, mBuilder.build());
}
}
public void onEventMainThread(DecryptingFileDoneEvent event) {
mAdapter.notifyItemChanged(event.index);
decryptCounter--;
if (decryptCounter == 0 && attached) {
Util.toast(context, getString(R.string.Files__save_to_SD), Toast.LENGTH_SHORT);
}
}
void decryptSelectedItems() {
for (final Integer index : mAdapter.getSelected()) {
decryptCounter++;
if (mAdapter.hasIndex(index)) {
if (attached) {
mAdapter.getItem(index).setIsDecrypting(true);
mAdapter.notifyItemChanged(index);
decrypt_and_save(index, new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new DecryptingFileDoneEvent(index));
}
});
}
}
}
}
void renameSelectedItems() {
for (final Integer index : mAdapter.getSelected()) {
decryptCounter++;
if (mAdapter.hasIndex(index)) {
if (attached) {
final EditText renameView = new EditText(context);
renameView.setText(mAdapter.getItem(index).getDecryptedFileName());
new AlertDialog.Builder(context)
.setTitle(getString(R.string.File__rename))
.setView(renameView)
.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String newName = renameView.getText().toString();
try {
mAdapter.getItem(index).rename(newName);
} catch (SecrecyCipherStreamException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
mAdapter.notifyItemChanged(index);
}
})
.setNegativeButton(R.string.CANCEL, Util.emptyClickListener)
.show();
}
}
}
}
void sendRawSelectedItems() {
ArrayList<DecryptArgHolder> Args = new ArrayList<DecryptArgHolder>();
for (final Integer index : mAdapter.getSelected()) {
if (mAdapter.hasIndex(index)) {
EncryptedFile encryptedFile = mAdapter.getItem(index);
final View mView = recyclerView.getChildAt(index);
if (!encryptedFile.getIsDecrypting()) {
switchView(mView, R.id.DecryptLayout);
ProgressBar pBar = mView != null ?
(ProgressBar) mView.findViewById(R.id.progressBar) :
null;
Runnable onFinish = new Runnable() {
@Override
public void run() {
switchView(mView, R.id.dataLayout);
}
};
Args.add(new DecryptArgHolder(encryptedFile, pBar, onFinish));
} else if (attached)
Util.toast(context, getString(R.string.Error__already_decrypting), Toast.LENGTH_SHORT);
}
}
if (attached)
sendMultiple(Args);
}
void selectAll() {
mAdapter.clearSelected();
for (int i = 0; i < mAdapter.getItemCount(); i++) {
select(i);
}
}
void deleteSelectedItems() {
// Hold a local copy of selected values, because action mode is left before
// Util.alter runs and thus adapter.getSelected is cleared.
final HashSet<Integer> selected = new HashSet<Integer>(mAdapter.getSelected());
final List<Integer> deleted = new ArrayList<>();
String FilesToDelete = "\n";
for (final Integer index : selected)
if (mAdapter.hasIndex(index))
FilesToDelete += "- " + mAdapter.getItem(index).getDecryptedFileName() + "\n";
Util.alert(context,
getString(R.string.Files__delete),
String.format(getString(R.string.Files__delete_message), FilesToDelete),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
for (final Integer index : selected) {
if (mAdapter.hasIndex(index))
if (!mAdapter.getItem(index).getIsDecrypting()) {
secret.deleteFile(mAdapter.getItem(index));
deleted.add(index);
} else if (attached)
Util.toast(context, getString(R.string.Error__already_decrypting_delete), Toast.LENGTH_SHORT);
}
// Don't modify adapter indices before finished.
mAdapter.remove(deleted);
}
},
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
}
);
}
@Override
void afterDecrypt(Intent newIntent, Intent altIntent) {
if (attached)
super.afterDecrypt(newIntent, altIntent); // check if fragment is attached.
}
void select(int position) {
mAdapter.select(position);
mAdapter.notifyItemChanged(position);
if (mActionMode == null)
return;
mActionMode.setTitle(
String.format(getString(R.string.Files__number_selected),
mAdapter.getSelected().size()));
MenuItem renameButton = mActionMode.getMenu().findItem(R.id.action_rename);
if (mAdapter.getSelected().size() == 1)
renameButton.setVisible(true);
else
renameButton.setVisible(false);
if (mAdapter.getSelected().size() == 0)
mActionMode.finish();
}
class DecryptArgHolder {
public final EncryptedFile encryptedFile;
public final ProgressBar pBar;
public final Runnable onFinish;
public DecryptArgHolder(EncryptedFile encryptedFile, ProgressBar pBar, Runnable onFinish) {
this.encryptedFile = encryptedFile;
this.pBar = pBar;
this.onFinish = onFinish;
}
}
public class OnBackPressedUnhandledEvent {
public final Activity activity;
public OnBackPressedUnhandledEvent(Activity activity) {
this.activity = activity;
}
}
}