summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle8
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/DividerItemDecoration.java5
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordEntry.java11
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java96
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordGeneratorDialogFragment.java48
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordStore.java230
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/SelectFolderFragment.java61
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java127
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ToCloneOrNot.kt10
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/UserPreference.kt215
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java4
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java190
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java123
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java103
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java130
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt143
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/CloneOperation.java8
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java131
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java4
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java120
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/PullOperation.java12
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/PushOperation.java11
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java10
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/config/GitConfigSessionFactory.java4
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/config/SshConfigSessionFactory.java1
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt310
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt25
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java45
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java12
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/Otp.java8
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java29
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java112
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java5
34 files changed, 925 insertions, 1428 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 030b1113..d138cc5d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,7 +7,7 @@ android {
compileSdkVersion 28
defaultConfig {
applicationId "com.zeapo.pwdstore"
- minSdkVersion 16
+ minSdkVersion 21
targetSdkVersion 28
versionCode 10302
versionName "1.3.2"
@@ -15,8 +15,8 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_7
- targetCompatibility JavaVersion.VERSION_1_7
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
abortOnError true // make sure build fails with lint errors!
@@ -79,8 +79,6 @@ dependencies {
androidTestImplementation 'androidx.test:rules:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0-alpha4'
-
-
}
repositories {
mavenCentral()
diff --git a/app/src/main/java/com/zeapo/pwdstore/DividerItemDecoration.java b/app/src/main/java/com/zeapo/pwdstore/DividerItemDecoration.java
index 21510112..93673902 100644
--- a/app/src/main/java/com/zeapo/pwdstore/DividerItemDecoration.java
+++ b/app/src/main/java/com/zeapo/pwdstore/DividerItemDecoration.java
@@ -4,9 +4,10 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.view.View;
+import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
-import android.view.View;
class DividerItemDecoration extends RecyclerView.ItemDecoration {
@@ -31,7 +32,7 @@ class DividerItemDecoration extends RecyclerView.ItemDecoration {
}
@Override
- public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.java b/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.java
index 590a779e..d876aefd 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.java
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.java
@@ -11,14 +11,13 @@ import java.io.UnsupportedEncodingException;
public class PasswordEntry {
private static final String[] USERNAME_FIELDS = new String[]{"login", "username"};
-
- private String extraContent;
private final String password;
private final String username;
private final String totpSecret;
private final String hotpSecret;
private final Long hotpCounter;
private final String content;
+ private String extraContent;
private boolean isIncremented = false;
public PasswordEntry(final ByteArrayOutputStream os) throws UnsupportedEncodingException {
@@ -34,7 +33,7 @@ public class PasswordEntry {
hotpCounter = findHotpCounter(content);
extraContent = findExtraContent(passContent);
username = findUsername();
- }
+ }
public String getPassword() {
return password;
@@ -76,7 +75,9 @@ public class PasswordEntry {
return hotpSecret != null && hotpCounter != null;
}
- public boolean hotpIsIncremented() { return isIncremented; }
+ public boolean hotpIsIncremented() {
+ return isIncremented;
+ }
public void incrementHotp() {
for (String line : content.split("\n")) {
@@ -126,7 +127,7 @@ public class PasswordEntry {
return null;
}
- private String findExtraContent(String [] passContent) {
+ private String findExtraContent(String[] passContent) {
String extraContent = passContent.length > 1 ? passContent[1] : "";
// if there is a HOTP URI, we must return the extra content with the counter incremented
if (hasHotp()) {
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java
index f6179703..63211af0 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java
@@ -4,16 +4,16 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import androidx.fragment.app.Fragment;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.zeapo.pwdstore.utils.PasswordItem;
import com.zeapo.pwdstore.utils.PasswordRecyclerAdapter;
import com.zeapo.pwdstore.utils.PasswordRepository;
@@ -24,16 +24,12 @@ import java.util.Stack;
/**
* A fragment representing a list of Items.
- * <p />
+ * <p/>
* Large screen devices (such as tablets) are supported by replacing the ListView
* with a GridView.
- * <p />
+ * <p/>
*/
-public class PasswordFragment extends Fragment{
-
- public interface OnFragmentInteractionListener {
- void onFragmentInteraction(PasswordItem item);
- }
+public class PasswordFragment extends Fragment {
// store the pass files list in a stack
private Stack<ArrayList<PasswordItem>> passListStack;
@@ -43,12 +39,12 @@ public class PasswordFragment extends Fragment{
private RecyclerView recyclerView;
private OnFragmentInteractionListener mListener;
private SharedPreferences settings;
-
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
- public PasswordFragment() { }
+ public PasswordFragment() {
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -60,18 +56,18 @@ public class PasswordFragment extends Fragment{
scrollPosition = new Stack<>();
pathStack = new Stack<>();
recyclerAdapter = new PasswordRecyclerAdapter((PasswordStore) getActivity(), mListener,
- PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
+ PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.password_recycler_view, container, false);
// use a linear layout manager
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
- recyclerView = (RecyclerView) view.findViewById(R.id.pass_recycler);
+ recyclerView = view.findViewById(R.id.pass_recycler);
recyclerView.setLayoutManager(mLayoutManager);
// use divider
@@ -80,13 +76,8 @@ public class PasswordFragment extends Fragment{
// Set the adapter
recyclerView.setAdapter(recyclerAdapter);
- final FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fab);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- ((PasswordStore) getActivity()).createPassword();
- }
- });
+ final FloatingActionButton fab = view.findViewById(R.id.fab);
+ fab.setOnClickListener(v -> ((PasswordStore) getActivity()).createPassword());
registerForContextMenu(recyclerView);
return view;
@@ -96,34 +87,32 @@ public class PasswordFragment extends Fragment{
public void onAttach(final Context context) {
super.onAttach(context);
try {
- mListener = new OnFragmentInteractionListener() {
- public void onFragmentInteraction(PasswordItem item) {
- if (item.getType() == PasswordItem.TYPE_CATEGORY) {
- // push the current password list (non filtered plz!)
- passListStack.push(pathStack.isEmpty() ?
- PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(context), getSortOrder()) :
- PasswordRepository.getPasswords(pathStack.peek(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
- //push the category were we're going
- pathStack.push(item.getFile());
- scrollPosition.push(recyclerView.getVerticalScrollbarPosition());
-
- recyclerView.scrollToPosition(0);
- recyclerAdapter.clear();
- recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
-
- ((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ mListener = item -> {
+ if (item.getType() == PasswordItem.TYPE_CATEGORY) {
+ // push the current password list (non filtered plz!)
+ passListStack.push(pathStack.isEmpty() ?
+ PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(context), getSortOrder()) :
+ PasswordRepository.getPasswords(pathStack.peek(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
+ //push the category were we're going
+ pathStack.push(item.getFile());
+ scrollPosition.push(recyclerView.getVerticalScrollbarPosition());
+
+ recyclerView.scrollToPosition(0);
+ recyclerAdapter.clear();
+ recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
+
+ ((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ } else {
+ if (getArguments().getBoolean("matchWith", false)) {
+ ((PasswordStore) getActivity()).matchPasswordWithApp(item);
} else {
- if (getArguments().getBoolean("matchWith", false)) {
- ((PasswordStore) getActivity()).matchPasswordWithApp(item);
- } else {
- ((PasswordStore) getActivity()).decryptPassword(item);
- }
+ ((PasswordStore) getActivity()).decryptPassword(item);
}
}
};
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
- + " must implement OnFragmentInteractionListener");
+ + " must implement OnFragmentInteractionListener");
}
}
@@ -146,12 +135,13 @@ public class PasswordFragment extends Fragment{
public void refreshAdapter() {
recyclerAdapter.clear();
recyclerAdapter.addAll(pathStack.isEmpty() ?
- PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()) :
- PasswordRepository.getPasswords(pathStack.peek(), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
+ PasswordRepository.getPasswords(PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()) :
+ PasswordRepository.getPasswords(pathStack.peek(), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
}
/**
* filters the list adapter
+ *
* @param filter the filter to apply
*/
public void filterAdapter(String filter) {
@@ -166,8 +156,9 @@ public class PasswordFragment extends Fragment{
/**
* recursively filters a directory and extract all the matching items
+ *
* @param filter the filter to apply
- * @param dir the directory to filter
+ * @param dir the directory to filter
*/
private void recursiveFilter(String filter, File dir) {
// on the root the pathStack is empty
@@ -205,6 +196,7 @@ public class PasswordFragment extends Fragment{
/**
* gets the current directory
+ *
* @return the current directory
*/
public File getCurrentDir() {
@@ -227,4 +219,8 @@ public class PasswordFragment extends Fragment{
private PasswordRepository.PasswordSortOrder getSortOrder() {
return PasswordRepository.PasswordSortOrder.getSortOrder(settings);
}
+
+ public interface OnFragmentInteractionListener {
+ void onFragmentInteraction(PasswordItem item);
+ }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordGeneratorDialogFragment.java b/app/src/main/java/com/zeapo/pwdstore/PasswordGeneratorDialogFragment.java
index 1a51f6f2..f161b927 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordGeneratorDialogFragment.java
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordGeneratorDialogFragment.java
@@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
@@ -30,7 +29,6 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
public PasswordGeneratorDialogFragment() {
}
-
@NotNull
@SuppressLint("SetTextI18n")
@Override
@@ -64,49 +62,35 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
TextView textView = view.findViewById(R.id.lengthNumber);
textView.setText(Integer.toString(prefs.getInt("length", 20)));
- ((TextView) view.findViewById(R.id.passwordText)).setTypeface(monoTypeface);
+ TextView passwordText = view.findViewById(R.id.passwordText);
+ passwordText.setTypeface(monoTypeface);
- builder.setPositiveButton(getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- EditText edit = callingActivity.findViewById(R.id.crypto_password_edit);
- TextView generate = view.findViewById(R.id.passwordText);
- edit.setText(generate.getText());
- }
+ builder.setPositiveButton(getResources().getString(R.string.dialog_ok), (dialog, which) -> {
+ EditText edit = callingActivity.findViewById(R.id.crypto_password_edit);
+ edit.setText(passwordText.getText());
});
- builder.setNegativeButton(getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
+ builder.setNegativeButton(getResources().getString(R.string.dialog_cancel), (dialog, which) -> {
- }
});
builder.setNeutralButton(getResources().getString(R.string.pwgen_generate), null);
final AlertDialog ad = builder.setTitle(this.getResources().getString(R.string.pwgen_title)).create();
- ad.setOnShowListener(new DialogInterface.OnShowListener() {
- @Override
- public void onShow(DialogInterface dialog) {
+ ad.setOnShowListener(dialog -> {
+ setPreferences();
+ passwordText.setText(PasswordGenerator.INSTANCE.generate(getActivity().getApplicationContext()).get(0));
+
+ Button b = ad.getButton(AlertDialog.BUTTON_NEUTRAL);
+ b.setOnClickListener(v -> {
setPreferences();
- TextView textView = view.findViewById(R.id.passwordText);
- textView.setText(PasswordGenerator.INSTANCE.generate(getActivity().getApplicationContext()).get(0));
-
- Button b = ad.getButton(AlertDialog.BUTTON_NEUTRAL);
- b.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setPreferences();
- TextView textView = view.findViewById(R.id.passwordText);
- textView.setText(PasswordGenerator.INSTANCE.generate(callingActivity.getApplicationContext()).get(0));
- }
- });
- }
+ passwordText.setText(PasswordGenerator.INSTANCE.generate(callingActivity.getApplicationContext()).get(0));
+ });
});
return ad;
}
- private void setPreferences () {
+ private void setPreferences() {
ArrayList<String> preferences = new ArrayList<>();
if (!((CheckBox) getDialog().findViewById(R.id.numerals)).isChecked()) {
preferences.add("0");
@@ -127,7 +111,7 @@ public class PasswordGeneratorDialogFragment extends DialogFragment {
try {
int length = Integer.valueOf(editText.getText().toString());
PasswordGenerator.INSTANCE.setPrefs(getActivity().getApplicationContext(), preferences, length);
- } catch(NumberFormatException e) {
+ } catch (NumberFormatException e) {
PasswordGenerator.INSTANCE.setPrefs(getActivity().getApplicationContext(), preferences);
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java
index a6e399ef..123acd2d 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java
@@ -3,7 +3,6 @@ package com.zeapo.pwdstore;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@@ -14,20 +13,6 @@ import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
-
-import androidx.annotation.NonNull;
-
-import com.google.android.material.snackbar.Snackbar;
-
-import androidx.core.app.ActivityCompat;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.MenuItemCompat;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.SearchView;
-
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -35,16 +20,23 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
-
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.SearchView;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.MenuItemCompat;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import com.google.android.material.snackbar.Snackbar;
import com.zeapo.pwdstore.crypto.PgpActivity;
import com.zeapo.pwdstore.git.GitActivity;
import com.zeapo.pwdstore.git.GitAsyncTask;
import com.zeapo.pwdstore.git.GitOperation;
-import com.zeapo.pwdstore.pwgen.PRNGFixes;
import com.zeapo.pwdstore.utils.PasswordItem;
import com.zeapo.pwdstore.utils.PasswordRecyclerAdapter;
import com.zeapo.pwdstore.utils.PasswordRepository;
-
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.eclipse.jgit.api.Git;
@@ -53,21 +45,15 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import java.io.File;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
public class PasswordStore extends AppCompatActivity {
- private static final String TAG = PasswordStore.class.getName();
- private SharedPreferences settings;
- private Activity activity;
- private PasswordFragment plist;
- private ShortcutManager shortcutManager;
- private MenuItem searchItem = null;
- private SearchView searchView;
-
- private final static int CLONE_REPO_BUTTON = 401;
- private final static int NEW_REPO_BUTTON = 402;
- private final static int HOME = 403;
public static final int REQUEST_CODE_SIGN = 9910;
public static final int REQUEST_CODE_ENCRYPT = 9911;
public static final int REQUEST_CODE_SIGN_AND_ENCRYPT = 9912;
@@ -76,6 +62,17 @@ public class PasswordStore extends AppCompatActivity {
public static final int REQUEST_CODE_GET_KEY_IDS = 9915;
public static final int REQUEST_CODE_EDIT = 9916;
public static final int REQUEST_CODE_SELECT_FOLDER = 9917;
+ private static final String TAG = PasswordStore.class.getName();
+ private final static int CLONE_REPO_BUTTON = 401;
+ private final static int NEW_REPO_BUTTON = 402;
+ private final static int HOME = 403;
+ private final static int REQUEST_EXTERNAL_STORAGE = 50;
+ private SharedPreferences settings;
+ private Activity activity;
+ private PasswordFragment plist;
+ private ShortcutManager shortcutManager;
+ private MenuItem searchItem = null;
+ private SearchView searchView;
private static boolean isPrintable(char c) {
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
@@ -106,8 +103,6 @@ public class PasswordStore extends AppCompatActivity {
return super.onKeyDown(keyCode, event);
}
- private final static int REQUEST_EXTERNAL_STORAGE = 50;
-
@Override
@SuppressLint("NewApi")
protected void onCreate(Bundle savedInstanceState) {
@@ -116,7 +111,6 @@ public class PasswordStore extends AppCompatActivity {
shortcutManager = getSystemService(ShortcutManager.class);
}
activity = this;
- PRNGFixes.INSTANCE.apply();
// If user opens app with permission granted then revokes and returns,
// prevent attempt to create password list fragment
@@ -142,17 +136,12 @@ public class PasswordStore extends AppCompatActivity {
// TODO: strings.xml
Snackbar snack = Snackbar.make(findViewById(R.id.main_layout), "The store is on the sdcard but the app does not have permission to access it. Please give permission.",
Snackbar.LENGTH_INDEFINITE)
- .setAction(R.string.dialog_ok, new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- ActivityCompat.requestPermissions(activity,
- new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
- REQUEST_EXTERNAL_STORAGE);
- }
- });
+ .setAction(R.string.dialog_ok, view -> ActivityCompat.requestPermissions(activity,
+ new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+ REQUEST_EXTERNAL_STORAGE));
snack.show();
View view = snack.getView();
- TextView tv = (TextView) view.findViewById(com.google.android.material.R.id.snackbar_text);
+ TextView tv = view.findViewById(com.google.android.material.R.id.snackbar_text);
tv.setTextColor(Color.WHITE);
tv.setMaxLines(10);
} else {
@@ -357,12 +346,9 @@ public class PasswordStore extends AppCompatActivity {
if (keyIds.isEmpty())
new AlertDialog.Builder(this)
.setMessage(this.getResources().getString(R.string.key_dialog_text))
- .setPositiveButton(this.getResources().getString(R.string.dialog_positive), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- Intent intent = new Intent(activity, UserPreference.class);
- startActivityForResult(intent, GitActivity.REQUEST_INIT);
- }
+ .setPositiveButton(this.getResources().getString(R.string.dialog_positive), (dialogInterface, i) -> {
+ Intent intent = new Intent(activity, UserPreference.class);
+ startActivityForResult(intent, GitActivity.REQUEST_INIT);
})
.setNegativeButton(this.getResources().getString(R.string.dialog_negative), null)
.show();
@@ -516,24 +502,18 @@ public class PasswordStore extends AppCompatActivity {
if (!PasswordRepository.isInitialized()) {
new AlertDialog.Builder(this)
.setMessage(this.getResources().getString(R.string.creation_dialog_text))
- .setPositiveButton(this.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- }
+ .setPositiveButton(this.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> {
}).show();
return;
}
- if (settings.getStringSet("openpgp_key_ids_set", new HashSet<String>()).isEmpty()) {
+ if (settings.getStringSet("openpgp_key_ids_set", new HashSet<>()).isEmpty()) {
new AlertDialog.Builder(this)
.setTitle(this.getResources().getString(R.string.no_key_selected_dialog_title))
.setMessage(this.getResources().getString(R.string.no_key_selected_dialog_text))
- .setPositiveButton(this.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- Intent intent = new Intent(activity, UserPreference.class);
- startActivity(intent);
- }
+ .setPositiveButton(this.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> {
+ Intent intent = new Intent(activity, UserPreference.class);
+ startActivity(intent);
}).show();
return;
}
@@ -559,25 +539,19 @@ public class PasswordStore extends AppCompatActivity {
new AlertDialog.Builder(this).
setMessage(this.getResources().getString(R.string.delete_dialog_text) +
item + "\"")
- .setPositiveButton(this.getResources().getString(R.string.dialog_yes), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- item.getFile().delete();
- adapter.remove(position);
- it.remove();
- adapter.updateSelectedItems(position, selectedItems);
-
- commitChange(getResources().getString(R.string.git_commit_remove_text,
- item.getLongName()));
- deletePasswords(adapter, selectedItems);
- }
+ .setPositiveButton(this.getResources().getString(R.string.dialog_yes), (dialogInterface, i) -> {
+ item.getFile().delete();
+ adapter.remove(position);
+ it.remove();
+ adapter.updateSelectedItems(position, selectedItems);
+
+ commitChange(getResources().getString(R.string.git_commit_remove_text,
+ item.getLongName()));
+ deletePasswords(adapter, selectedItems);
})
- .setNegativeButton(this.getResources().getString(R.string.dialog_no), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- it.remove();
- deletePasswords(adapter, selectedItems);
- }
+ .setNegativeButton(this.getResources().getString(R.string.dialog_no), (dialogInterface, i) -> {
+ it.remove();
+ deletePasswords(adapter, selectedItems);
})
.show();
}
@@ -771,64 +745,54 @@ public class PasswordStore extends AppCompatActivity {
new AlertDialog.Builder(this)
.setTitle(this.getResources().getString(R.string.location_dialog_title))
.setMessage(this.getResources().getString(R.string.location_dialog_text))
- .setPositiveButton(this.getResources().getString(R.string.location_hidden), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- settings.edit().putBoolean("git_external", false).apply();
-
- switch (operation) {
- case NEW_REPO_BUTTON:
- initializeRepositoryInfo();
- break;
- case CLONE_REPO_BUTTON:
- PasswordRepository.initialize(PasswordStore.this);
-
- Intent intent = new Intent(activity, GitActivity.class);
- intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
- startActivityForResult(intent, GitActivity.REQUEST_CLONE);
- break;
- }
+ .setPositiveButton(this.getResources().getString(R.string.location_hidden), (dialog, whichButton) -> {
+ settings.edit().putBoolean("git_external", false).apply();
+
+ switch (operation) {
+ case NEW_REPO_BUTTON:
+ initializeRepositoryInfo();
+ break;
+ case CLONE_REPO_BUTTON:
+ PasswordRepository.initialize(PasswordStore.this);
+
+ Intent intent = new Intent(activity, GitActivity.class);
+ intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
+ startActivityForResult(intent, GitActivity.REQUEST_CLONE);
+ break;
}
})
- .setNegativeButton(this.getResources().getString(R.string.location_sdcard), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- settings.edit().putBoolean("git_external", true).apply();
-
- String externalRepo = settings.getString("git_external_repo", null);
-
- if (externalRepo == null) {
- Intent intent = new Intent(activity, UserPreference.class);
- intent.putExtra("operation", "git_external");
- startActivityForResult(intent, operation);
- } else {
- new AlertDialog.Builder(activity)
- .setTitle(getResources().getString(R.string.directory_selected_title))
- .setMessage(getResources().getString(R.string.directory_selected_message, externalRepo))
- .setPositiveButton(getResources().getString(R.string.use), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (operation) {
- case NEW_REPO_BUTTON:
- initializeRepositoryInfo();
- break;
- case CLONE_REPO_BUTTON:
- PasswordRepository.initialize(PasswordStore.this);
-
- Intent intent = new Intent(activity, GitActivity.class);
- intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
- startActivityForResult(intent, GitActivity.REQUEST_CLONE);
- break;
- }
- }
- })
- .setNegativeButton(getResources().getString(R.string.change), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Intent intent = new Intent(activity, UserPreference.class);
- intent.putExtra("operation", "git_external");
- startActivityForResult(intent, operation);
- }
- }).show();
- }
+ .setNegativeButton(this.getResources().getString(R.string.location_sdcard), (dialog, whichButton) -> {
+ settings.edit().putBoolean("git_external", true).apply();
+
+ String externalRepo = settings.getString("git_external_repo", null);
+
+ if (externalRepo == null) {
+ Intent intent = new Intent(activity, UserPreference.class);
+ intent.putExtra("operation", "git_external");
+ startActivityForResult(intent, operation);
+ } else {
+ new AlertDialog.Builder(activity)
+ .setTitle(getResources().getString(R.string.directory_selected_title))
+ .setMessage(getResources().getString(R.string.directory_selected_message, externalRepo))
+ .setPositiveButton(getResources().getString(R.string.use), (dialog1, which) -> {
+ switch (operation) {
+ case NEW_REPO_BUTTON:
+ initializeRepositoryInfo();
+ break;
+ case CLONE_REPO_BUTTON:
+ PasswordRepository.initialize(PasswordStore.this);
+
+ Intent intent = new Intent(activity, GitActivity.class);
+ intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
+ startActivityForResult(intent, GitActivity.REQUEST_CLONE);
+ break;
+ }
+ })
+ .setNegativeButton(getResources().getString(R.string.change), (dialog12, which) -> {
+ Intent intent = new Intent(activity, UserPreference.class);
+ intent.putExtra("operation", "git_external");
+ startActivityForResult(intent, operation);
+ }).show();
}
})
.show();
diff --git a/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt b/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt
index 30923ee1..2e894987 100644
--- a/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt
@@ -2,9 +2,9 @@ package com.zeapo.pwdstore
import android.app.Activity
import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
+import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentManager
import com.zeapo.pwdstore.utils.PasswordRepository
diff --git a/app/src/main/java/com/zeapo/pwdstore/SelectFolderFragment.java b/app/src/main/java/com/zeapo/pwdstore/SelectFolderFragment.java
index f4ec98b2..1fe79a2a 100644
--- a/app/src/main/java/com/zeapo/pwdstore/SelectFolderFragment.java
+++ b/app/src/main/java/com/zeapo/pwdstore/SelectFolderFragment.java
@@ -1,50 +1,44 @@
package com.zeapo.pwdstore;
import android.content.Context;
-import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import androidx.fragment.app.Fragment;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.zeapo.pwdstore.utils.FolderRecyclerAdapter;
import com.zeapo.pwdstore.utils.PasswordItem;
import com.zeapo.pwdstore.utils.PasswordRepository;
import java.io.File;
-import java.util.ArrayList;
import java.util.Stack;
/**
* A fragment representing a list of Items.
- * <p />
+ * <p/>
* Large screen devices (such as tablets) are supported by replacing the ListView
* with a GridView.
- * <p />
+ * <p/>
*/
-public class SelectFolderFragment extends Fragment{
-
- public interface OnFragmentInteractionListener {
- void onFragmentInteraction(PasswordItem item);
- }
+public class SelectFolderFragment extends Fragment {
// store the pass files list in a stack
private Stack<File> pathStack;
private FolderRecyclerAdapter recyclerAdapter;
private RecyclerView recyclerView;
private OnFragmentInteractionListener mListener;
-
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
- public SelectFolderFragment() { }
+ public SelectFolderFragment() {
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -53,11 +47,11 @@ public class SelectFolderFragment extends Fragment{
pathStack = new Stack<>();
recyclerAdapter = new FolderRecyclerAdapter((SelectFolderActivity) getActivity(), mListener,
- PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
+ PasswordRepository.getPasswords(new File(path), PasswordRepository.getRepositoryDirectory(getActivity()), getSortOrder()));
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.password_recycler_view, container, false);
@@ -81,28 +75,27 @@ public class SelectFolderFragment extends Fragment{
public void onAttach(final Context context) {
super.onAttach(context);
try {
- mListener = new OnFragmentInteractionListener() {
- public void onFragmentInteraction(PasswordItem item) {
- if (item.getType() == PasswordItem.TYPE_CATEGORY) {
- //push the category were we're going
- pathStack.push(item.getFile());
-
- recyclerView.scrollToPosition(0);
- recyclerAdapter.clear();
- recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
-
- ((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- }
+ mListener = item -> {
+ if (item.getType() == PasswordItem.TYPE_CATEGORY) {
+ //push the category were we're going
+ pathStack.push(item.getFile());
+
+ recyclerView.scrollToPosition(0);
+ recyclerAdapter.clear();
+ recyclerAdapter.addAll(PasswordRepository.getPasswords(item.getFile(), PasswordRepository.getRepositoryDirectory(context), getSortOrder()));
+
+ ((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
};
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
- + " must implement OnFragmentInteractionListener");
+ + " must implement OnFragmentInteractionListener");
}
}
/**
* gets the current directory
+ *
* @return the current directory
*/
public File getCurrentDir() {
@@ -115,4 +108,8 @@ public class SelectFolderFragment extends Fragment{
private PasswordRepository.PasswordSortOrder getSortOrder() {
return PasswordRepository.PasswordSortOrder.getSortOrder(PreferenceManager.getDefaultSharedPreferences(getActivity()));
}
+
+ public interface OnFragmentInteractionListener {
+ void onFragmentInteraction(PasswordItem item);
+ }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java b/app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java
index 72d1c024..476ca6b1 100644
--- a/app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java
+++ b/app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java
@@ -8,14 +8,11 @@ import android.app.ProgressDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
@@ -24,15 +21,14 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
-import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
-
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.KeyPair;
-
import org.apache.commons.io.FileUtils;
import java.io.File;
@@ -41,6 +37,34 @@ import java.lang.ref.WeakReference;
public class SshKeyGen extends AppCompatActivity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (getSupportActionBar() != null)
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+ setTitle("Generate SSH Key");
+
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, new SshKeyGenFragment()).commit();
+ }
+ }
+
+ // Invoked when 'Generate' button of SshKeyGenFragment clicked. Generates a
+ // private and public key, then replaces the SshKeyGenFragment with a
+ // ShowSshKeyFragment which displays the public key.
+ public void generate(View view) {
+ String length = Integer.toString((Integer) ((Spinner) findViewById(R.id.length)).getSelectedItem());
+ String passphrase = ((EditText) findViewById(R.id.passphrase)).getText().toString();
+ String comment = ((EditText) findViewById(R.id.comment)).getText().toString();
+ new KeyGenerateTask(this).execute(length, passphrase, comment);
+
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
+
// SSH key generation UI
public static class SshKeyGenFragment extends Fragment {
public SshKeyGenFragment() {
@@ -61,18 +85,15 @@ public class SshKeyGen extends AppCompatActivity {
((EditText) v.findViewById(R.id.passphrase)).setTypeface(monoTypeface);
CheckBox checkbox = v.findViewById(R.id.show_passphrase);
- checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- EditText editText = v.findViewById(R.id.passphrase);
- int selection = editText.getSelectionEnd();
- if (isChecked) {
- editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
- } else {
- editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
- }
- editText.setSelection(selection);
+ checkbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ EditText editText = v.findViewById(R.id.passphrase);
+ int selection = editText.getSelectionEnd();
+ if (isChecked) {
+ editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+ } else {
+ editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
+ editText.setSelection(selection);
});
return v;
@@ -100,59 +121,31 @@ public class SshKeyGen extends AppCompatActivity {
e.printStackTrace();
}
- builder.setPositiveButton(getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (getActivity() instanceof SshKeyGen)
- getActivity().finish();
- }
+ builder.setPositiveButton(getResources().getString(R.string.dialog_ok), (dialog, which) -> {
+ if (getActivity() instanceof SshKeyGen)
+ getActivity().finish();
});
- builder.setNegativeButton(getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
+ builder.setNegativeButton(getResources().getString(R.string.dialog_cancel), (dialog, which) -> {
- }
});
builder.setNeutralButton(getResources().getString(R.string.ssh_keygen_copy), null);
final AlertDialog ad = builder.setTitle("Your public key").create();
- ad.setOnShowListener(new DialogInterface.OnShowListener() {
- @Override
- public void onShow(DialogInterface dialog) {
- Button b = ad.getButton(AlertDialog.BUTTON_NEUTRAL);
- b.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- TextView textView = getDialog().findViewById(R.id.public_key);
- ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText("public key", textView.getText().toString());
- clipboard.setPrimaryClip(clip);
- }
- });
- }
+ ad.setOnShowListener(dialog -> {
+ Button b = ad.getButton(AlertDialog.BUTTON_NEUTRAL);
+ b.setOnClickListener(v1 -> {
+ TextView textView1 = getDialog().findViewById(R.id.public_key);
+ ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText("public key", textView1.getText().toString());
+ clipboard.setPrimaryClip(clip);
+ });
});
return ad;
}
}
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (getSupportActionBar() != null)
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- setTitle("Generate SSH Key");
-
- if (savedInstanceState == null) {
- getFragmentManager().beginTransaction()
- .replace(android.R.id.content, new SshKeyGenFragment()).commit();
- }
- }
-
private static class KeyGenerateTask extends AsyncTask<String, Void, Exception> {
private ProgressDialog pd;
private WeakReference<SshKeyGen> weakReference;
@@ -211,27 +204,11 @@ public class SshKeyGen extends AppCompatActivity {
new AlertDialog.Builder(weakReference.get())
.setTitle("Error while trying to generate the ssh-key")
.setMessage(weakReference.get().getResources().getString(R.string.ssh_key_error_dialog_text) + e.getMessage())
- .setPositiveButton(weakReference.get().getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- // pass
- }
+ .setPositiveButton(weakReference.get().getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> {
+ // pass
}).show();
}
}
}
-
- // Invoked when 'Generate' button of SshKeyGenFragment clicked. Generates a
- // private and public key, then replaces the SshKeyGenFragment with a
- // ShowSshKeyFragment which displays the public key.
- public void generate(View view) {
- String length = Integer.toString((Integer) ((Spinner) findViewById(R.id.length)).getSelectedItem());
- String passphrase = ((EditText) findViewById(R.id.passphrase)).getText().toString();
- String comment = ((EditText) findViewById(R.id.comment)).getText().toString();
- new KeyGenerateTask(this).execute(length, passphrase, comment);
-
- InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
- }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/ToCloneOrNot.kt b/app/src/main/java/com/zeapo/pwdstore/ToCloneOrNot.kt
index 3df845f2..75a7d4fc 100644
--- a/app/src/main/java/com/zeapo/pwdstore/ToCloneOrNot.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/ToCloneOrNot.kt
@@ -1,18 +1,18 @@
package com.zeapo.pwdstore
import android.os.Bundle
-import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-
+import androidx.fragment.app.Fragment
class ToCloneOrNot : Fragment() {
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?): View? {
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_to_clone_or_not, container, false)
}
-
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
index 69a1cf1a..d93d6bcc 100644
--- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
@@ -15,16 +15,16 @@ import android.preference.Preference
import android.preference.PreferenceFragment
import android.preference.PreferenceManager
import android.provider.Settings
-import com.google.android.material.snackbar.Snackbar
-import androidx.core.app.ActivityCompat
-import androidx.core.content.ContextCompat
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.app.AppCompatActivity
import android.util.Log
import android.view.MenuItem
import android.view.accessibility.AccessibilityManager
import android.widget.TextView
import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import com.google.android.material.snackbar.Snackbar
import com.nononsenseapps.filepicker.FilePickerActivity
import com.zeapo.pwdstore.autofill.AutofillPreferenceActivity
import com.zeapo.pwdstore.crypto.PgpActivity
@@ -36,8 +36,9 @@ import org.openintents.openpgp.util.OpenPgpUtils
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
-import java.util.*
-import kotlin.collections.HashSet
+import java.util.ArrayList
+import java.util.Date
+import java.util.Locale
class UserPreference : AppCompatActivity() {
private lateinit var prefsFragment: PrefsFragment
@@ -75,17 +76,19 @@ class UserPreference : AppCompatActivity() {
true
}
- findPreference("ssh_key_clear_passphrase").onPreferenceClickListener = Preference.OnPreferenceClickListener {
- sharedPreferences.edit().putString("ssh_key_passphrase", null).apply()
- it.isEnabled = false
- true
- }
+ findPreference("ssh_key_clear_passphrase").onPreferenceClickListener =
+ Preference.OnPreferenceClickListener {
+ sharedPreferences.edit().putString("ssh_key_passphrase", null).apply()
+ it.isEnabled = false
+ true
+ }
- findPreference("hotp_remember_clear_choice").onPreferenceClickListener = Preference.OnPreferenceClickListener {
- sharedPreferences.edit().putBoolean("hotp_remember_check", false).apply()
- it.isEnabled = false
- true
- }
+ findPreference("hotp_remember_clear_choice").onPreferenceClickListener =
+ Preference.OnPreferenceClickListener {
+ sharedPreferences.edit().putBoolean("hotp_remember_check", false).apply()
+ it.isEnabled = false
+ true
+ }
findPreference("git_server_info").onPreferenceClickListener = Preference.OnPreferenceClickListener {
val intent = Intent(callingActivity, GitActivity::class.java)
@@ -104,28 +107,30 @@ class UserPreference : AppCompatActivity() {
findPreference("git_delete_repo").onPreferenceClickListener = Preference.OnPreferenceClickListener {
val repoDir = PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext)
AlertDialog.Builder(callingActivity)
- .setTitle(R.string.pref_dialog_delete_title)
- .setMessage("${resources.getString(R.string.dialog_delete_msg)} \n $repoDir")
- .setCancelable(false)
- .setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
- try {
- FileUtils.cleanDirectory(PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext))
- PasswordRepository.closeRepository()
- } catch (e: Exception) {
- //TODO Handle the diffent cases of exceptions
- }
-
- sharedPreferences.edit().putBoolean("repository_initialized", false).apply()
- dialogInterface.cancel()
- callingActivity.finish()
- }.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
- .show()
+ .setTitle(R.string.pref_dialog_delete_title)
+ .setMessage("${resources.getString(R.string.dialog_delete_msg)} \n $repoDir")
+ .setCancelable(false)
+ .setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
+ try {
+ FileUtils.cleanDirectory(PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext))
+ PasswordRepository.closeRepository()
+ } catch (e: Exception) {
+ //TODO Handle the diffent cases of exceptions
+ }
+
+ sharedPreferences.edit().putBoolean("repository_initialized", false).apply()
+ dialogInterface.cancel()
+ callingActivity.finish()
+ }
+ .setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
+ .show()
true
}
val externalRepo = findPreference("pref_select_external")
- externalRepo.summary = sharedPreferences.getString("git_external_repo", callingActivity.getString(R.string.no_repo_selected))
+ externalRepo.summary =
+ sharedPreferences.getString("git_external_repo", callingActivity.getString(R.string.no_repo_selected))
externalRepo.onPreferenceClickListener = Preference.OnPreferenceClickListener {
callingActivity.selectExternalGitRepository()
true
@@ -148,10 +153,14 @@ class UserPreference : AppCompatActivity() {
}
findPreference("autofill_enable").onPreferenceClickListener = Preference.OnPreferenceClickListener {
- AlertDialog.Builder(callingActivity).setTitle(R.string.pref_autofill_enable_title).setView(R.layout.autofill_instructions).setPositiveButton(R.string.dialog_ok) { _, _ ->
+ AlertDialog.Builder(callingActivity).setTitle(R.string.pref_autofill_enable_title)
+ .setView(R.layout.autofill_instructions).setPositiveButton(R.string.dialog_ok) { _, _ ->
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
startActivity(intent)
- }.setNegativeButton(R.string.dialog_cancel, null).setOnDismissListener { (findPreference("autofill_enable") as CheckBoxPreference).isChecked = (activity as UserPreference).isServiceEnabled }.show()
+ }.setNegativeButton(R.string.dialog_cancel, null).setOnDismissListener {
+ (findPreference("autofill_enable") as CheckBoxPreference).isChecked =
+ (activity as UserPreference).isServiceEnabled
+ }.show()
true
}
@@ -164,24 +173,34 @@ class UserPreference : AppCompatActivity() {
override fun onStart() {
super.onStart()
val sharedPreferences = preferenceManager.sharedPreferences
- findPreference("pref_select_external").summary = preferenceManager.sharedPreferences.getString("git_external_repo", getString(R.string.no_repo_selected))
+ findPreference("pref_select_external").summary =
+ preferenceManager.sharedPreferences.getString("git_external_repo", getString(R.string.no_repo_selected))
findPreference("ssh_see_key").isEnabled = sharedPreferences.getBoolean("use_generated_key", false)
findPreference("git_delete_repo").isEnabled = !sharedPreferences.getBoolean("git_external", false)
- findPreference("ssh_key_clear_passphrase").isEnabled = sharedPreferences.getString("ssh_key_passphrase", null)?.isNotEmpty() ?: false
- findPreference("hotp_remember_clear_choice").isEnabled = sharedPreferences.getBoolean("hotp_remember_check", false)
+ findPreference("ssh_key_clear_passphrase").isEnabled = sharedPreferences.getString(
+ "ssh_key_passphrase",
+ null
+ )?.isNotEmpty() ?: false
+ findPreference("hotp_remember_clear_choice").isEnabled =
+ sharedPreferences.getBoolean("hotp_remember_check", false)
val keyPref = findPreference("openpgp_key_id_pref")
- val selectedKeys: Array<String> = ArrayList<String>(sharedPreferences.getStringSet("openpgp_key_ids_set", HashSet<String>())).toTypedArray()
+ val selectedKeys: Array<String> = ArrayList<String>(
+ sharedPreferences.getStringSet(
+ "openpgp_key_ids_set",
+ HashSet<String>()
+ )
+ ).toTypedArray()
if (selectedKeys.isEmpty()) {
keyPref.summary = this.resources.getString(R.string.pref_no_key_selected)
} else {
- keyPref.summary = selectedKeys.joinToString(separator = ";") {
- s ->
+ keyPref.summary = selectedKeys.joinToString(separator = ";") { s ->
OpenPgpUtils.convertKeyIdToHex(java.lang.Long.valueOf(s))
}
}
// see if the autofill service is enabled and check the preference accordingly
- (findPreference("autofill_enable") as CheckBoxPreference).isChecked = (activity as UserPreference).isServiceEnabled
+ (findPreference("autofill_enable") as CheckBoxPreference).isChecked =
+ (activity as UserPreference).isServiceEnabled
}
}
@@ -203,24 +222,23 @@ class UserPreference : AppCompatActivity() {
fun selectExternalGitRepository() {
val activity = this
AlertDialog.Builder(this)
- .setTitle(this.resources.getString(R.string.external_repository_dialog_title))
- .setMessage(this.resources.getString(R.string.external_repository_dialog_text))
- .setPositiveButton(R.string.dialog_ok) { _, _ ->
- // This always works
- val i = Intent(activity.applicationContext, FilePickerActivity::class.java)
- // This works if you defined the intent filter
- // Intent i = new Intent(Intent.ACTION_GET_CONTENT);
-
- // Set these depending on your use case. These are the defaults.
- i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
- i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
- i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
-
- i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().path)
-
- startActivityForResult(i, SELECT_GIT_DIRECTORY)
- }.setNegativeButton(R.string.dialog_cancel, null).show()
-
+ .setTitle(this.resources.getString(R.string.external_repository_dialog_title))
+ .setMessage(this.resources.getString(R.string.external_repository_dialog_text))
+ .setPositiveButton(R.string.dialog_ok) { _, _ ->
+ // This always works
+ val i = Intent(activity.applicationContext, FilePickerActivity::class.java)
+ // This works if you defined the intent filter
+ // Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+
+ // Set these depending on your use case. These are the defaults.
+ i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
+ i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
+ i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
+
+ i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().path)
+
+ startActivityForResult(i, SELECT_GIT_DIRECTORY)
+ }.setNegativeButton(R.string.dialog_cancel, null).show()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -242,9 +260,9 @@ class UserPreference : AppCompatActivity() {
* Opens a file explorer to import the private key
*/
fun getSshKeyWithPermissions(useDefaultPicker: Boolean) = runWithPermissions(
- requestedPermission = Manifest.permission.READ_EXTERNAL_STORAGE,
- requestCode = REQUEST_EXTERNAL_STORAGE_SSH_KEY,
- reason = "We need access to the sd-card to import the ssh-key"
+ requestedPermission = Manifest.permission.READ_EXTERNAL_STORAGE,
+ requestCode = REQUEST_EXTERNAL_STORAGE_SSH_KEY,
+ reason = "We need access to the sd-card to import the ssh-key"
) {
getSshKey(useDefaultPicker)
}
@@ -282,9 +300,9 @@ class UserPreference : AppCompatActivity() {
if (ContextCompat.checkSelfPermission(this, requestedPermission) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, requestedPermission)) {
val snack = Snackbar.make(prefsFragment.view, reason, Snackbar.LENGTH_INDEFINITE)
- .setAction(R.string.dialog_ok) {
- ActivityCompat.requestPermissions(this, arrayOf(requestedPermission), requestCode)
- }
+ .setAction(R.string.dialog_ok) {
+ ActivityCompat.requestPermissions(this, arrayOf(requestedPermission), requestCode)
+ }
snack.show()
val view = snack.view
val tv = view.findViewById<TextView>(com.google.android.material.R.id.snackbar_text)
@@ -297,16 +315,15 @@ class UserPreference : AppCompatActivity() {
} else {
body()
}
-
}
/**
* Exports the passwords after requesting permissions
*/
fun exportPasswordsWithPermissions() = runWithPermissions(
- requestedPermission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
- requestCode = REQUEST_EXTERNAL_STORAGE_SSH_KEY,
- reason = "We need access to the sd-card to export the passwords"
+ requestedPermission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ requestCode = REQUEST_EXTERNAL_STORAGE_SSH_KEY,
+ reason = "We need access to the sd-card to export the passwords"
) {
exportPasswords()
}
@@ -355,15 +372,16 @@ class UserPreference : AppCompatActivity() {
private val isServiceEnabled: Boolean
get() {
val am = this
- .getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
+ .getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
val runningServices = am
- .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC)
+ .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC)
return runningServices.any { "com.zeapo.pwdstore/.autofill.AutofillService" == it.id }
}
-
- override fun onActivityResult(requestCode: Int, resultCode: Int,
- data: Intent?) {
+ override fun onActivityResult(
+ requestCode: Int, resultCode: Int,
+ data: Intent?
+ ) {
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
setResult(Activity.RESULT_CANCELED)
@@ -376,7 +394,11 @@ class UserPreference : AppCompatActivity() {
val uri: Uri = data.data ?: throw IOException("Unable to open file")
copySshKey(uri)
- Toast.makeText(this, this.resources.getString(R.string.ssh_key_success_dialog_title), Toast.LENGTH_LONG).show()
+ Toast.makeText(
+ this,
+ this.resources.getString(R.string.ssh_key_success_dialog_title),
+ Toast.LENGTH_LONG
+ ).show()
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
prefs.edit().putBoolean("use_generated_key", false).apply()
@@ -388,11 +410,13 @@ class UserPreference : AppCompatActivity() {
finish()
} catch (e: IOException) {
- AlertDialog.Builder(this).setTitle(this.resources.getString(R.string.ssh_key_error_dialog_title)).setMessage(this.resources.getString(R.string.ssh_key_error_dialog_text) + e.message).setPositiveButton(this.resources.getString(R.string.dialog_ok)) { _, _ ->
- // pass
- }.show()
+ AlertDialog.Builder(this)
+ .setTitle(this.resources.getString(R.string.ssh_key_error_dialog_title))
+ .setMessage(this.resources.getString(R.string.ssh_key_error_dialog_text) + e.message)
+ .setPositiveButton(this.resources.getString(R.string.dialog_ok)) { _, _ ->
+ // pass
+ }.show()
}
-
}
EDIT_GIT_INFO -> {
@@ -403,21 +427,23 @@ class UserPreference : AppCompatActivity() {
if (uri?.path == Environment.getExternalStorageDirectory().path) {
// the user wants to use the root of the sdcard as a store...
AlertDialog.Builder(this)
- .setTitle("SD-Card root selected")
- .setMessage("You have selected the root of your sdcard for the store. " +
- "This is extremely dangerous and you will lose your data " +
- "as its content will, eventually, be deleted")
- .setPositiveButton("Remove everything") { _, _ ->
- PreferenceManager.getDefaultSharedPreferences(applicationContext)
- .edit()
- .putString("git_external_repo", uri?.path)
- .apply()
- }.setNegativeButton(R.string.dialog_cancel, null).show()
+ .setTitle("SD-Card root selected")
+ .setMessage(
+ "You have selected the root of your sdcard for the store. " +
+ "This is extremely dangerous and you will lose your data " +
+ "as its content will, eventually, be deleted"
+ )
+ .setPositiveButton("Remove everything") { _, _ ->
+ PreferenceManager.getDefaultSharedPreferences(applicationContext)
+ .edit()
+ .putString("git_external_repo", uri?.path)
+ .apply()
+ }.setNegativeButton(R.string.dialog_cancel, null).show()
} else {
PreferenceManager.getDefaultSharedPreferences(applicationContext)
- .edit()
- .putString("git_external_repo", uri?.path)
- .apply()
+ .edit()
+ .putString("git_external_repo", uri?.path)
+ .apply()
}
}
EXPORT_PASSWORDS -> {
@@ -433,7 +459,6 @@ class UserPreference : AppCompatActivity() {
} catch (e: IOException) {
Log.d("PWD_EXPORT", "Exception happened : " + e.message)
}
-
}
}
else -> {
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java
index 0d39e01d..12d1de74 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillActivity.java
@@ -6,11 +6,9 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.os.Bundle;
-import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
-
+import androidx.appcompat.app.AppCompatActivity;
import com.zeapo.pwdstore.PasswordStore;
-
import org.eclipse.jgit.util.StringUtils;
import java.util.ArrayList;
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java
index 3a3b632d..d7095dae 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillFragment.java
@@ -5,18 +5,13 @@ import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
-import androidx.appcompat.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
@@ -24,7 +19,9 @@ import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
-
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.content.ContextCompat;
import com.zeapo.pwdstore.PasswordStore;
import com.zeapo.pwdstore.R;
@@ -84,12 +81,7 @@ public class AutofillFragment extends DialogFragment {
((ListView) view.findViewById(R.id.matched)).setAdapter(adapter);
// delete items by clicking them
((ListView) view.findViewById(R.id.matched)).setOnItemClickListener(
- new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- adapter.remove(adapter.getItem(position));
- }
- });
+ (parent, view1, position, id) -> adapter.remove(adapter.getItem(position)));
// set the existing preference, if any
SharedPreferences prefs;
@@ -116,36 +108,27 @@ public class AutofillFragment extends DialogFragment {
}
// add items with the + button
- View.OnClickListener matchPassword = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- ((RadioButton) view.findViewById(R.id.match)).toggle();
- Intent intent = new Intent(getActivity(), PasswordStore.class);
- intent.putExtra("matchWith", true);
- startActivityForResult(intent, MATCH_WITH);
- }
+ View.OnClickListener matchPassword = v -> {
+ ((RadioButton) view.findViewById(R.id.match)).toggle();
+ Intent intent = new Intent(getActivity(), PasswordStore.class);
+ intent.putExtra("matchWith", true);
+ startActivityForResult(intent, MATCH_WITH);
};
view.findViewById(R.id.matchButton).setOnClickListener(matchPassword);
// write to preferences when OK clicked
- builder.setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
+ builder.setPositiveButton(R.string.dialog_ok, (dialog, which) -> {
- }
});
builder.setNegativeButton(R.string.dialog_cancel, null);
final SharedPreferences.Editor editor = prefs.edit();
if (isWeb) {
- builder.setNeutralButton(R.string.autofill_apps_delete, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (callingActivity.recyclerAdapter != null
- && packageName != null && !packageName.equals("")) {
- editor.remove(packageName);
- callingActivity.recyclerAdapter.removeWebsite(packageName);
- editor.apply();
- }
+ builder.setNeutralButton(R.string.autofill_apps_delete, (dialog, which) -> {
+ if (callingActivity.recyclerAdapter != null
+ && packageName != null && !packageName.equals("")) {
+ editor.remove(packageName);
+ callingActivity.recyclerAdapter.removeWebsite(packageName);
+ editor.apply();
}
});
}
@@ -157,91 +140,88 @@ public class AutofillFragment extends DialogFragment {
public void onStart() {
super.onStart();
AlertDialog ad = (AlertDialog) getDialog();
- if(ad != null) {
+ if (ad != null) {
Button positiveButton = ad.getButton(Dialog.BUTTON_POSITIVE);
- positiveButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity();
- Dialog dialog = getDialog();
-
- SharedPreferences prefs;
- if (!isWeb) {
- prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE);
- } else {
- prefs = getActivity().getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE);
- }
- SharedPreferences.Editor editor = prefs.edit();
+ positiveButton.setOnClickListener(v -> {
+ AutofillPreferenceActivity callingActivity = (AutofillPreferenceActivity) getActivity();
+ Dialog dialog = getDialog();
+
+ SharedPreferences prefs;
+ if (!isWeb) {
+ prefs = getActivity().getApplicationContext().getSharedPreferences("autofill", Context.MODE_PRIVATE);
+ } else {
+ prefs = getActivity().getApplicationContext().getSharedPreferences("autofill_web", Context.MODE_PRIVATE);
+ }
+ SharedPreferences.Editor editor = prefs.edit();
- String packageName = getArguments().getString("packageName", "");
- if (isWeb) {
- // handle some errors and don't dismiss the dialog
- EditText webURL = (EditText) dialog.findViewById(R.id.webURL);
+ String packageName = getArguments().getString("packageName", "");
+ if (isWeb) {
+ // handle some errors and don't dismiss the dialog
+ EditText webURL = dialog.findViewById(R.id.webURL);
- packageName = webURL.getText().toString();
+ packageName = webURL.getText().toString();
- if (packageName.equals("")) {
- webURL.setError("URL cannot be blank");
- return;
- }
- String oldPackageName = getArguments().getString("packageName", "");
- if (!oldPackageName.equals(packageName) && prefs.getAll().containsKey(packageName)) {
- webURL.setError("URL already exists");
- return;
- }
+ if (packageName.equals("")) {
+ webURL.setError("URL cannot be blank");
+ return;
}
-
- // write to preferences accordingly
- RadioGroup radioGroup = (RadioGroup) dialog.findViewById(R.id.autofill_radiogroup);
- switch (radioGroup.getCheckedRadioButtonId()) {
- case R.id.use_default:
- if (!isWeb) {
- editor.remove(packageName);
- } else {
- editor.putString(packageName, "");
- }
- break;
- case R.id.first:
- editor.putString(packageName, "/first");
- break;
- case R.id.never:
- editor.putString(packageName, "/never");
- break;
- default:
- StringBuilder paths = new StringBuilder();
- for (int i = 0; i < adapter.getCount(); i++) {
- paths.append(adapter.getItem(i));
- if (i != adapter.getCount()) {
- paths.append("\n");
- }
- }
- editor.putString(packageName, paths.toString());
+ String oldPackageName = getArguments().getString("packageName", "");
+ if (!oldPackageName.equals(packageName) && prefs.getAll().containsKey(packageName)) {
+ webURL.setError("URL already exists");
+ return;
}
- editor.apply();
+ }
- // notify the recycler adapter if it is loaded
- if (callingActivity.recyclerAdapter != null) {
- int position;
+ // write to preferences accordingly
+ RadioGroup radioGroup = dialog.findViewById(R.id.autofill_radiogroup);
+ switch (radioGroup.getCheckedRadioButtonId()) {
+ case R.id.use_default:
if (!isWeb) {
- String appName = getArguments().getString("appName", "");
- position = callingActivity.recyclerAdapter.getPosition(appName);
- callingActivity.recyclerAdapter.notifyItemChanged(position);
+ editor.remove(packageName);
} else {
- position = callingActivity.recyclerAdapter.getPosition(packageName);
- String oldPackageName = getArguments().getString("packageName", "");
- if (oldPackageName.equals(packageName)) {
- callingActivity.recyclerAdapter.notifyItemChanged(position);
- } else if (oldPackageName.equals("")){
- callingActivity.recyclerAdapter.addWebsite(packageName);
- } else {
- editor.remove(oldPackageName);
- callingActivity.recyclerAdapter.updateWebsite(oldPackageName, packageName);
+ editor.putString(packageName, "");
+ }
+ break;
+ case R.id.first:
+ editor.putString(packageName, "/first");
+ break;
+ case R.id.never:
+ editor.putString(packageName, "/never");
+ break;
+ default:
+ StringBuilder paths = new StringBuilder();
+ for (int i = 0; i < adapter.getCount(); i++) {
+ paths.append(adapter.getItem(i));
+ if (i != adapter.getCount()) {
+ paths.append("\n");
}
}
- }
+ editor.putString(packageName, paths.toString());
+ }
+ editor.apply();
- dismiss();
+ // notify the recycler adapter if it is loaded
+ if (callingActivity.recyclerAdapter != null) {
+ int position;
+ if (!isWeb) {
+ String appName = getArguments().getString("appName", "");
+ position = callingActivity.recyclerAdapter.getPosition(appName);
+ callingActivity.recyclerAdapter.notifyItemChanged(position);
+ } else {
+ position = callingActivity.recyclerAdapter.getPosition(packageName);
+ String oldPackageName = getArguments().getString("packageName", "");
+ if (oldPackageName.equals(packageName)) {
+ callingActivity.recyclerAdapter.notifyItemChanged(position);
+ } else if (oldPackageName.equals("")) {
+ callingActivity.recyclerAdapter.addWebsite(packageName);
+ } else {
+ editor.remove(oldPackageName);
+ callingActivity.recyclerAdapter.updateWebsite(oldPackageName, packageName);
+ }
+ }
}
+
+ dismiss();
});
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java
index b85a31c7..9fba959a 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillPreferenceActivity.java
@@ -8,19 +8,18 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.os.Bundle;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.SearchView;
import androidx.core.app.NavUtils;
import androidx.core.app.TaskStackBuilder;
import androidx.core.view.MenuItemCompat;
-import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import androidx.appcompat.widget.SearchView;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.zeapo.pwdstore.R;
import java.util.ArrayList;
@@ -29,9 +28,8 @@ import java.util.Map;
public class AutofillPreferenceActivity extends AppCompatActivity {
- private RecyclerView recyclerView;
AutofillRecyclerAdapter recyclerAdapter; // let fragment have access
-
+ private RecyclerView recyclerView;
private PackageManager pm;
private boolean recreate; // flag for action on up press; origin autofill dialog? different act
@@ -41,7 +39,7 @@ public class AutofillPreferenceActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.autofill_recycler_view);
- recyclerView = (RecyclerView) findViewById(R.id.autofill_recycler);
+ recyclerView = findViewById(R.id.autofill_recycler);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
@@ -62,64 +60,8 @@ public class AutofillPreferenceActivity extends AppCompatActivity {
setTitle("Autofill Apps");
- final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showDialog("", "", true);
- }
- });
- }
-
- private class populateTask extends AsyncTask<Void, Void, Void> {
- @Override
- protected void onPreExecute() {
- runOnUiThread(new Runnable() {
- public void run() {
- findViewById(R.id.progress_bar).setVisibility(View.VISIBLE);
- }
- });
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- List<ResolveInfo> allAppsResolveInfo = pm.queryIntentActivities(intent, 0);
- List<AutofillRecyclerAdapter.AppInfo> allApps = new ArrayList<>();
-
- for (ResolveInfo app : allAppsResolveInfo) {
- allApps.add(new AutofillRecyclerAdapter.AppInfo(app.activityInfo.packageName
- , app.loadLabel(pm).toString(), false, app.loadIcon(pm)));
- }
-
- SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE);
- Map<String, ?> prefsMap = prefs.getAll();
- for (String key : prefsMap.keySet()) {
- try {
- allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, pm.getApplicationIcon("com.android.browser")));
- } catch (PackageManager.NameNotFoundException e) {
- allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, null));
- }
- }
-
- recyclerAdapter = new AutofillRecyclerAdapter(allApps, pm, AutofillPreferenceActivity.this);
- return null;
- }
-
- @Override
- protected void onPostExecute(Void aVoid) {
- runOnUiThread(new Runnable() {
- public void run() {
- findViewById(R.id.progress_bar).setVisibility(View.GONE);
- recyclerView.setAdapter(recyclerAdapter);
- Bundle extras = getIntent().getExtras();
- if (extras != null) {
- recyclerView.scrollToPosition(recyclerAdapter.getPosition(extras.getString("appName")));
- }
- }
- });
- }
+ final FloatingActionButton fab = findViewById(R.id.fab);
+ fab.setOnClickListener(v -> showDialog("", "", true));
}
@Override
@@ -175,4 +117,49 @@ public class AutofillPreferenceActivity extends AppCompatActivity {
df.setArguments(args);
df.show(getFragmentManager(), "autofill_dialog");
}
+
+ private class populateTask extends AsyncTask<Void, Void, Void> {
+ @Override
+ protected void onPreExecute() {
+ runOnUiThread(() -> findViewById(R.id.progress_bar).setVisibility(View.VISIBLE));
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> allAppsResolveInfo = pm.queryIntentActivities(intent, 0);
+ List<AutofillRecyclerAdapter.AppInfo> allApps = new ArrayList<>();
+
+ for (ResolveInfo app : allAppsResolveInfo) {
+ allApps.add(new AutofillRecyclerAdapter.AppInfo(app.activityInfo.packageName
+ , app.loadLabel(pm).toString(), false, app.loadIcon(pm)));
+ }
+
+ SharedPreferences prefs = getSharedPreferences("autofill_web", Context.MODE_PRIVATE);
+ Map<String, ?> prefsMap = prefs.getAll();
+ for (String key : prefsMap.keySet()) {
+ try {
+ allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, pm.getApplicationIcon("com.android.browser")));
+ } catch (PackageManager.NameNotFoundException e) {
+ allApps.add(new AutofillRecyclerAdapter.AppInfo(key, key, true, null));
+ }
+ }
+
+ recyclerAdapter = new AutofillRecyclerAdapter(allApps, pm, AutofillPreferenceActivity.this);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ runOnUiThread(() -> {
+ findViewById(R.id.progress_bar).setVisibility(View.GONE);
+ recyclerView.setAdapter(recyclerAdapter);
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ recyclerView.scrollToPosition(recyclerAdapter.getPosition(extras.getString("appName")));
+ }
+ });
+ }
+ }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java
index 0c1ec224..bed2aa7e 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillRecyclerAdapter.java
@@ -4,15 +4,14 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import androidx.recyclerview.widget.SortedList;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.SortedListAdapterCallback;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.SortedList;
+import androidx.recyclerview.widget.SortedListAdapterCallback;
import com.zeapo.pwdstore.R;
import java.util.ArrayList;
@@ -25,50 +24,6 @@ class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecyclerAdapt
private AutofillPreferenceActivity activity;
private Drawable browserIcon = null;
- class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
- public View view;
- public TextView name;
- TextView secondary;
- public ImageView icon;
- String packageName;
- String appName;
- Boolean isWeb;
-
- ViewHolder(View view) {
- super(view);
- this.view = view;
- name = (TextView) view.findViewById(R.id.app_name);
- secondary = (TextView) view.findViewById(R.id.secondary_text);
- icon = (ImageView) view.findViewById(R.id.app_icon);
- view.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- activity.showDialog(packageName, appName, isWeb);
- }
-
- }
-
- static class AppInfo {
- String packageName;
- String appName;
- boolean isWeb;
- public Drawable icon;
-
- AppInfo(String packageName, String appName, boolean isWeb, Drawable icon) {
- this.packageName = packageName;
- this.appName = appName;
- this.isWeb = isWeb;
- this.icon = icon;
- }
-
- @Override
- public boolean equals(Object o) {
- return o != null && o instanceof AppInfo && this.appName.equals(((AppInfo) o).appName);
- }
- }
-
AutofillRecyclerAdapter(List<AppInfo> allApps, final PackageManager pm
, AutofillPreferenceActivity activity) {
SortedList.Callback<AppInfo> callback = new SortedListAdapterCallback<AppInfo>(this) {
@@ -76,17 +31,17 @@ class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecyclerAdapt
// for the limited add/remove usage for websites
@Override
public int compare(AppInfo o1, AppInfo o2) {
- return o1.appName.toLowerCase().compareTo(o2.appName.toLowerCase());
+ return o1.appName.toLowerCase().compareTo(o2.appName.toLowerCase());
}
@Override
public boolean areContentsTheSame(AppInfo oldItem, AppInfo newItem) {
- return oldItem.appName.equals(newItem.appName);
+ return oldItem.appName.equals(newItem.appName);
}
@Override
public boolean areItemsTheSame(AppInfo item1, AppInfo item2) {
- return item1.appName.equals(item2.appName);
+ return item1.appName.equals(item2.appName);
}
};
this.apps = new SortedList<>(AppInfo.class, callback);
@@ -170,7 +125,7 @@ class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecyclerAdapt
}
void updateWebsite(String oldPackageName, String packageName) {
- apps.updateItemAt(getPosition(oldPackageName), new AppInfo (packageName, packageName, true, browserIcon));
+ apps.updateItemAt(getPosition(oldPackageName), new AppInfo(packageName, packageName, true, browserIcon));
allApps.remove(new AppInfo(null, oldPackageName, false, null)); // compare with equals
allApps.add(new AppInfo(null, packageName, false, null));
}
@@ -190,4 +145,48 @@ class AutofillRecyclerAdapter extends RecyclerView.Adapter<AutofillRecyclerAdapt
}
apps.endBatchedUpdates();
}
+
+ static class AppInfo {
+ public Drawable icon;
+ String packageName;
+ String appName;
+ boolean isWeb;
+
+ AppInfo(String packageName, String appName, boolean isWeb, Drawable icon) {
+ this.packageName = packageName;
+ this.appName = appName;
+ this.isWeb = isWeb;
+ this.icon = icon;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof AppInfo && this.appName.equals(((AppInfo) o).appName);
+ }
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+ public View view;
+ public TextView name;
+ public ImageView icon;
+ TextView secondary;
+ String packageName;
+ String appName;
+ Boolean isWeb;
+
+ ViewHolder(View view) {
+ super(view);
+ this.view = view;
+ name = view.findViewById(R.id.app_name);
+ secondary = view.findViewById(R.id.secondary_text);
+ icon = view.findViewById(R.id.app_icon);
+ view.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ activity.showDialog(packageName, appName, isWeb);
+ }
+
+ }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java
index 7a4d59fa..8ad27b4f 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.java
@@ -1,12 +1,10 @@
package com.zeapo.pwdstore.autofill;
import android.accessibilityservice.AccessibilityService;
-import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
@@ -16,18 +14,16 @@ import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.Settings;
-import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.widget.Toast;
-
+import androidx.appcompat.app.AlertDialog;
import com.zeapo.pwdstore.PasswordEntry;
import com.zeapo.pwdstore.R;
import com.zeapo.pwdstore.utils.PasswordRepository;
-
import org.apache.commons.io.FileUtils;
import org.openintents.openpgp.IOpenPgpService2;
import org.openintents.openpgp.OpenPgpError;
@@ -62,10 +58,6 @@ public class AutofillService extends AccessibilityService {
private PasswordEntry lastPassword;
private long lastPasswordMaxDate;
- final class Constants {
- static final String TAG = "Keychain";
- }
-
public static AutofillService getInstance() {
return instance;
}
@@ -96,11 +88,6 @@ public class AutofillService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
- // TODO there should be a better way of disabling service
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
- return;
- }
-
// remove stored password from cache
if (lastPassword != null && System.currentTimeMillis() > lastPasswordMaxDate) {
lastPassword = null;
@@ -405,20 +392,14 @@ public class AutofillService extends AccessibilityService {
}
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog);
- builder.setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface d, int which) {
- dialog.dismiss();
- dialog = null;
- }
+ builder.setNegativeButton(R.string.dialog_cancel, (d, which) -> {
+ dialog.dismiss();
+ dialog = null;
});
- builder.setPositiveButton(R.string.autofill_paste, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface d, int which) {
- pasteText(node, password.getUsername());
- dialog.dismiss();
- dialog = null;
- }
+ builder.setPositiveButton(R.string.autofill_paste, (d, which) -> {
+ pasteText(node, password.getUsername());
+ dialog.dismiss();
+ dialog = null;
});
builder.setMessage(getString(R.string.autofill_paste_username, password.getUsername()));
@@ -436,24 +417,19 @@ public class AutofillService extends AccessibilityService {
}
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog);
- builder.setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface d, int which) {
- dialog.dismiss();
- dialog = null;
- }
+ builder.setNegativeButton(R.string.dialog_cancel, (d, which) -> {
+ dialog.dismiss();
+ dialog = null;
});
- builder.setNeutralButton("Settings", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) { //TODO make icon? gear?
- // the user will have to return to the app themselves.
- Intent intent = new Intent(AutofillService.this, AutofillPreferenceActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.putExtra("packageName", packageName);
- intent.putExtra("appName", appName);
- intent.putExtra("isWeb", isWeb);
- startActivity(intent);
- }
+ builder.setNeutralButton("Settings", (dialog, which) -> {
+ //TODO make icon? gear?
+ // the user will have to return to the app themselves.
+ Intent intent = new Intent(AutofillService.this, AutofillPreferenceActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra("packageName", packageName);
+ intent.putExtra("appName", appName);
+ intent.putExtra("isWeb", isWeb);
+ startActivity(intent);
});
// populate the dialog items, always with pick + pick and match. Could
@@ -464,26 +440,23 @@ public class AutofillService extends AccessibilityService {
}
itemNames[items.size()] = getString(R.string.autofill_pick);
itemNames[items.size() + 1] = getString(R.string.autofill_pick_and_match);
- builder.setItems(itemNames, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- lastWhichItem = which;
- if (which < items.size()) {
- bindDecryptAndVerify();
- } else if (which == items.size()) {
- Intent intent = new Intent(AutofillService.this, AutofillActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.putExtra("pick", true);
- startActivity(intent);
- } else {
- lastWhichItem--; // will add one element to items, so lastWhichItem=items.size()+1
- Intent intent = new Intent(AutofillService.this, AutofillActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.putExtra("pickMatchWith", true);
- intent.putExtra("packageName", packageName);
- intent.putExtra("isWeb", isWeb);
- startActivity(intent);
- }
+ builder.setItems(itemNames, (dialog, which) -> {
+ lastWhichItem = which;
+ if (which < items.size()) {
+ bindDecryptAndVerify();
+ } else if (which == items.size()) {
+ Intent intent = new Intent(AutofillService.this, AutofillActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra("pick", true);
+ startActivity(intent);
+ } else {
+ lastWhichItem--; // will add one element to items, so lastWhichItem=items.size()+1
+ Intent intent = new Intent(AutofillService.this, AutofillActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.putExtra("pickMatchWith", true);
+ intent.putExtra("packageName", packageName);
+ intent.putExtra("isWeb", isWeb);
+ startActivity(intent);
}
});
@@ -515,18 +488,6 @@ public class AutofillService extends AccessibilityService {
}
- private class onBoundListener implements OpenPgpServiceConnection.OnBound {
- @Override
- public void onBound(IOpenPgpService2 service) {
- decryptAndVerify();
- }
-
- @Override
- public void onError(Exception e) {
- e.printStackTrace();
- }
- }
-
private void bindDecryptAndVerify() {
if (serviceConnection.getService() == null) {
// the service was disconnected, need to bind again
@@ -600,7 +561,6 @@ public class AutofillService extends AccessibilityService {
}
}
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void pasteText(final AccessibilityNodeInfo node, final String text) {
// if the user focused on something else, take focus back
// but this will open another dialog...hack to ignore this
@@ -627,4 +587,20 @@ public class AutofillService extends AccessibilityService {
}
node.recycle();
}
+
+ final class Constants {
+ static final String TAG = "Keychain";
+ }
+
+ private class onBoundListener implements OpenPgpServiceConnection.OnBound {
+ @Override
+ public void onBound(IOpenPgpService2 service) {
+ decryptAndVerify();
+ }
+
+ @Override
+ public void onError(Exception e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
index 63fff21d..9be1f170 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
@@ -32,9 +32,9 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.zeapo.pwdstore.PasswordEntry
+import com.zeapo.pwdstore.PasswordGeneratorDialogFragment
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.UserPreference
-import com.zeapo.pwdstore.PasswordGeneratorDialogFragment
import com.zeapo.pwdstore.utils.Otp
import kotlinx.android.synthetic.main.decrypt_layout.*
import kotlinx.android.synthetic.main.encrypt_layout.*
@@ -73,7 +73,14 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
private val fullPath: String by lazy { intent.getStringExtra("FILE_PATH") }
private val name: String by lazy { getName(fullPath) }
- private val lastChangedString: CharSequence by lazy { getLastChangedString(intent.getIntExtra("LAST_CHANGED_TIMESTAMP", -1)) }
+ private val lastChangedString: CharSequence by lazy {
+ getLastChangedString(
+ intent.getIntExtra(
+ "LAST_CHANGED_TIMESTAMP",
+ -1
+ )
+ )
+ }
private val relativeParentPath: String by lazy { getParentPath(fullPath, repoPath) }
private val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
@@ -122,7 +129,6 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
crypto_password_category.text = getRelativePath(fullPath, repoPath)
}
}
-
}
override fun onDestroy() {
@@ -147,7 +153,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
android.R.id.home -> {
- if(passwordEntry?.hotpIsIncremented() == false) {
+ if (passwordEntry?.hotpIsIncremented() == false) {
setResult(RESULT_CANCELED)
}
finish()
@@ -157,7 +163,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
R.id.edit_password -> editPassword()
R.id.crypto_confirm_add -> encrypt()
R.id.crypto_cancel_add -> {
- if(passwordEntry?.hotpIsIncremented() == false) {
+ if (passwordEntry?.hotpIsIncremented() == false) {
setResult(RESULT_CANCELED)
}
finish()
@@ -186,8 +192,9 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
val pi: PendingIntent = result.getParcelableExtra(RESULT_INTENT)
try {
this@PgpActivity.startIntentSenderFromChild(
- this@PgpActivity, pi.intentSender, requestCode,
- null, 0, 0, 0)
+ this@PgpActivity, pi.intentSender, requestCode,
+ null, 0, 0, 0
+ )
} catch (e: IntentSender.SendIntentException) {
Log.e(TAG, "SendIntentException", e)
}
@@ -258,8 +265,8 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
null
} else {
HoldToShowPasswordTransformation(
- crypto_password_toggle_show,
- Runnable { crypto_password_show.text = entry.password }
+ crypto_password_toggle_show,
+ Runnable { crypto_password_show.text = entry.password }
)
}
@@ -277,8 +284,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
crypto_copy_username.setOnClickListener { copyUsernameToClipBoard(entry.username) }
crypto_username_show.typeface = monoTypeface
crypto_username_show.text = entry.username
- }
- else {
+ } else {
crypto_username_show.visibility = View.GONE
crypto_username_show_label.visibility = View.GONE
crypto_copy_username.visibility = View.GONE
@@ -295,8 +301,16 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
crypto_copy_otp.visibility = View.VISIBLE
if (entry.hasTotp()) {
- crypto_copy_otp.setOnClickListener { copyOtpToClipBoard(Otp.calculateCode(entry.totpSecret, Date().time / (1000 * Otp.TIME_WINDOW))) }
- crypto_otp_show.text = Otp.calculateCode(entry.totpSecret, Date().time / (1000 * Otp.TIME_WINDOW))
+ crypto_copy_otp.setOnClickListener {
+ copyOtpToClipBoard(
+ Otp.calculateCode(
+ entry.totpSecret,
+ Date().time / (1000 * Otp.TIME_WINDOW)
+ )
+ )
+ }
+ crypto_otp_show.text =
+ Otp.calculateCode(entry.totpSecret, Date().time / (1000 * Otp.TIME_WINDOW))
} else {
// we only want to calculate and show HOTP if the user requests it
crypto_copy_otp.setOnClickListener {
@@ -310,22 +324,23 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
// show a dialog asking permission to update the HOTP counter in the entry
val checkInflater = LayoutInflater.from(this)
val checkLayout = checkInflater.inflate(R.layout.otp_confirm_layout, null)
- val rememberCheck : CheckBox = checkLayout.findViewById(R.id.hotp_remember_checkbox)
+ val rememberCheck: CheckBox =
+ checkLayout.findViewById(R.id.hotp_remember_checkbox)
val dialogBuilder = AlertDialog.Builder(this)
dialogBuilder.setView(checkLayout)
dialogBuilder.setMessage(R.string.dialog_update_body)
- .setCancelable(false)
- .setPositiveButton(R.string.dialog_update_positive) { _, _ ->
- run {
- calculateAndCommitHotp(entry)
- if (rememberCheck.isChecked) {
- val editor = settings.edit()
- editor.putBoolean("hotp_remember_check", true)
- editor.putBoolean("hotp_remember_choice", true)
- editor.apply()
- }
+ .setCancelable(false)
+ .setPositiveButton(R.string.dialog_update_positive) { _, _ ->
+ run {
+ calculateAndCommitHotp(entry)
+ if (rememberCheck.isChecked) {
+ val editor = settings.edit()
+ editor.putBoolean("hotp_remember_check", true)
+ editor.putBoolean("hotp_remember_choice", true)
+ editor.apply()
}
}
+ }
.setNegativeButton(R.string.dialog_update_negative) { _, _ ->
run {
calculateHotp(entry)
@@ -343,7 +358,6 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
crypto_otp_show.setText(R.string.hotp_pending)
}
crypto_otp_show.typeface = monoTypeface
-
} else {
crypto_otp_show.visibility = View.GONE
crypto_otp_show_label.visibility = View.GONE
@@ -353,7 +367,6 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
if (settings.getBoolean("copy_on_decrypt", true)) {
copyPasswordToClipBoard()
}
-
} catch (e: Exception) {
Log.e(TAG, "An Exception occurred", e)
}
@@ -370,7 +383,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
*/
private fun encrypt() {
// if HOTP was incremented, we leave fields as is; they have already been set
- if(intent.getStringExtra("OPERATION") != "INCREMENT") {
+ if (intent.getStringExtra("OPERATION") != "INCREMENT") {
editName = crypto_password_file_edit.text.toString().trim()
editPass = crypto_password_edit.text.toString()
editExtra = crypto_extra_edit.text.toString()
@@ -400,37 +413,37 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
val path = if (intent.getBooleanExtra("fromDecrypt", false)) fullPath else "$fullPath/$editName.gpg"
- api?.executeApiAsync(data, iStream, oStream) { result: Intent? -> when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
- OpenPgpApi.RESULT_CODE_SUCCESS -> {
- try {
- // TODO This might fail, we should check that the write is successful
- val outputStream = FileUtils.openOutputStream(File(path))
- outputStream.write(oStream.toByteArray())
- outputStream.close()
-
- val returnIntent = Intent()
- returnIntent.putExtra("CREATED_FILE", path)
- returnIntent.putExtra("NAME", editName)
- returnIntent.putExtra("LONG_NAME", getLongName(fullPath, repoPath, this.editName!!))
-
- // if coming from decrypt screen->edit button
- if (intent.getBooleanExtra("fromDecrypt", false)) {
- returnIntent.putExtra("OPERATION", "EDIT")
- returnIntent.putExtra("needCommit", true)
+ api?.executeApiAsync(data, iStream, oStream) { result: Intent? ->
+ when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
+ OpenPgpApi.RESULT_CODE_SUCCESS -> {
+ try {
+ // TODO This might fail, we should check that the write is successful
+ val outputStream = FileUtils.openOutputStream(File(path))
+ outputStream.write(oStream.toByteArray())
+ outputStream.close()
+
+ val returnIntent = Intent()
+ returnIntent.putExtra("CREATED_FILE", path)
+ returnIntent.putExtra("NAME", editName)
+ returnIntent.putExtra("LONG_NAME", getLongName(fullPath, repoPath, this.editName!!))
+
+ // if coming from decrypt screen->edit button
+ if (intent.getBooleanExtra("fromDecrypt", false)) {
+ returnIntent.putExtra("OPERATION", "EDIT")
+ returnIntent.putExtra("needCommit", true)
+ }
+ setResult(RESULT_OK, returnIntent)
+ finish()
+ } catch (e: Exception) {
+ Log.e(TAG, "An Exception occurred", e)
}
- setResult(RESULT_OK, returnIntent)
- finish()
- } catch (e: Exception) {
- Log.e(TAG, "An Exception occurred", e)
}
+ OpenPgpApi.RESULT_CODE_ERROR -> handleError(result)
}
- OpenPgpApi.RESULT_CODE_ERROR -> handleError(result)
- }
}
}
-
/**
* Opens EncryptActivity with the information for this file to be edited
*/
@@ -467,7 +480,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
private fun checkAndIncrementHotp() {
// we do not want to increment the HOTP counter if the user has edited the entry or has not
// generated an HOTP code
- if(intent.getStringExtra("OPERATION") != "EDIT" && passwordEntry?.hotpIsIncremented() == true) {
+ if (intent.getStringExtra("OPERATION") != "EDIT" && passwordEntry?.hotpIsIncremented() == true) {
editName = name.trim()
editPass = passwordEntry?.password
editExtra = passwordEntry?.extraContent
@@ -480,13 +493,13 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
}
}
- private fun calculateHotp(entry : PasswordEntry) {
+ private fun calculateHotp(entry: PasswordEntry) {
copyOtpToClipBoard(Otp.calculateCode(entry.hotpSecret, entry.hotpCounter + 1))
crypto_otp_show.text = Otp.calculateCode(entry.hotpSecret, entry.hotpCounter + 1)
crypto_extra_show.text = entry.extraContent
}
- private fun calculateAndCommitHotp(entry : PasswordEntry) {
+ private fun calculateAndCommitHotp(entry: PasswordEntry) {
calculateHotp(entry)
entry.incrementHotp()
// we must set the result before encrypt() is called, since in
@@ -568,7 +581,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
}
private inner class HoldToShowPasswordTransformation constructor(button: Button, private val onToggle: Runnable) :
- PasswordTransformationMethod(), View.OnTouchListener {
+ PasswordTransformationMethod(), View.OnTouchListener {
private var shown = false
init {
@@ -634,7 +647,12 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra(Intent.EXTRA_TEXT, passwordEntry?.password)
sendIntent.type = "text/plain"
- startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_plaintext_password_to)))//Always show a picker to give the user a chance to cancel
+ startActivity(
+ Intent.createChooser(
+ sendIntent,
+ resources.getText(R.string.send_plaintext_password_to)
+ )
+ )//Always show a picker to give the user a chance to cancel
}
private fun setTimer() {
@@ -673,7 +691,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
// This signals the DelayShow task to stop and avoids it having
// to poll the AsyncTask.isCancelled() excessively. If skipClearing
// is true, the cancelled task won't clear the clipboard.
- fun cancelAndSignal(skipClearing : Boolean) {
+ fun cancelAndSignal(skipClearing: Boolean) {
skip = skipClearing
cancelNotify.open()
}
@@ -710,7 +728,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
while (current < showTime) {
// Block for 1s or until cancel is signalled
- if(cancelNotify.block(1000)) {
+ if (cancelNotify.block(1000)) {
Log.d("DELAY_SHOW", "Cancelled")
return true
}
@@ -734,14 +752,17 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
val handler = Handler()
for (i in 0..18) {
val count = i.toString()
- handler.postDelayed({ clipboard.primaryClip = ClipData.newPlainText(count, count) }, (i * 500).toLong())
+ handler.postDelayed(
+ { clipboard.primaryClip = ClipData.newPlainText(count, count) },
+ (i * 500).toLong()
+ )
}
}
}
if (crypto_password_show != null) {
// clear password; if decrypt changed to encrypt layout via edit button, no need
- if(passwordEntry?.hotpIsIncremented() == false) {
+ if (passwordEntry?.hotpIsIncremented() == false) {
setResult(AppCompatActivity.RESULT_CANCELED)
}
passwordEntry = null
@@ -771,7 +792,7 @@ class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
* Gets the relative path to the repository
*/
fun getRelativePath(fullPath: String, repositoryPath: String): String =
- fullPath.replace(repositoryPath, "").replace("/+".toRegex(), "/")
+ fullPath.replace(repositoryPath, "").replace("/+".toRegex(), "/")
/**
* Gets the Parent path, relative to the repository
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/CloneOperation.java b/app/src/main/java/com/zeapo/pwdstore/git/CloneOperation.java
index c3f22a64..e3de3f05 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/CloneOperation.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/CloneOperation.java
@@ -2,10 +2,7 @@ package com.zeapo.pwdstore.git;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.DialogInterface;
-
import com.zeapo.pwdstore.R;
-
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
@@ -79,10 +76,7 @@ public class CloneOperation extends GitOperation {
+ callingActivity.getResources().getString(R.string.jgit_error_dialog_text)
+ errorMessage
+ "\nPlease check the FAQ for possible reasons why this error might occur.").
- setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- }
+ setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> {
}).show();
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
index b6e9af82..ca451247 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
@@ -2,13 +2,10 @@ package com.zeapo.pwdstore.git;
import android.app.Activity;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
@@ -20,11 +17,11 @@ import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
-
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
import com.zeapo.pwdstore.R;
import com.zeapo.pwdstore.UserPreference;
import com.zeapo.pwdstore.utils.PasswordRepository;
-
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RebaseCommand;
@@ -39,29 +36,24 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GitActivity extends AppCompatActivity {
+ public static final int REQUEST_PULL = 101;
+ public static final int REQUEST_PUSH = 102;
+ public static final int REQUEST_CLONE = 103;
+ public static final int REQUEST_INIT = 104;
+ public static final int EDIT_SERVER = 105;
+ public static final int REQUEST_SYNC = 106;
+ public static final int REQUEST_CREATE = 107;
+ public static final int EDIT_GIT_CONFIG = 108;
private static final String TAG = "GitAct";
private static final String emailPattern = "^[^@]+@[^@]+$";
-
private Activity activity;
private Context context;
-
private String protocol;
private String connectionMode;
-
private File localDir;
private String hostname;
-
private SharedPreferences settings;
- public static final int REQUEST_PULL = 101;
- public static final int REQUEST_PUSH = 102;
- public static final int REQUEST_CLONE = 103;
- public static final int REQUEST_INIT = 104;
- public static final int EDIT_SERVER = 105;
- public static final int REQUEST_SYNC = 106;
- public static final int REQUEST_CREATE = 107;
- public static final int EDIT_GIT_CONFIG = 108;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -83,8 +75,8 @@ public class GitActivity extends AppCompatActivity {
setContentView(R.layout.activity_git_clone);
setTitle(R.string.title_activity_git_clone);
- final Spinner protcol_spinner = (Spinner) findViewById(R.id.clone_protocol);
- final Spinner connection_mode_spinner = (Spinner) findViewById(R.id.connection_mode);
+ final Spinner protcol_spinner = findViewById(R.id.clone_protocol);
+ final Spinner connection_mode_spinner = findViewById(R.id.connection_mode);
// init the spinner for connection modes
final ArrayAdapter<CharSequence> connection_mode_adapter = ArrayAdapter.createFromResource(this,
@@ -157,11 +149,11 @@ public class GitActivity extends AppCompatActivity {
}
// init the server information
- final EditText server_url = ((EditText) findViewById(R.id.server_url));
- final EditText server_port = ((EditText) findViewById(R.id.server_port));
- final EditText server_path = ((EditText) findViewById(R.id.server_path));
- final EditText server_user = ((EditText) findViewById(R.id.server_user));
- final EditText server_uri = ((EditText) findViewById(R.id.clone_uri));
+ final EditText server_url = findViewById(R.id.server_url);
+ final EditText server_port = findViewById(R.id.server_port);
+ final EditText server_path = findViewById(R.id.server_path);
+ final EditText server_user = findViewById(R.id.server_user);
+ final EditText server_uri = findViewById(R.id.clone_uri);
server_url.setText(settings.getString("git_remote_server", ""));
server_port.setText(settings.getString("git_remote_port", ""));
@@ -282,11 +274,11 @@ public class GitActivity extends AppCompatActivity {
* Fills in the server_uri field with the information coming from other fields
*/
private void updateURI() {
- EditText uri = (EditText) findViewById(R.id.clone_uri);
- EditText server_url = ((EditText) findViewById(R.id.server_url));
- EditText server_port = ((EditText) findViewById(R.id.server_port));
- EditText server_path = ((EditText) findViewById(R.id.server_path));
- EditText server_user = ((EditText) findViewById(R.id.server_user));
+ EditText uri = findViewById(R.id.clone_uri);
+ EditText server_url = findViewById(R.id.server_url);
+ EditText server_port = findViewById(R.id.server_port);
+ EditText server_path = findViewById(R.id.server_path);
+ EditText server_user = findViewById(R.id.server_user);
if (uri != null) {
switch (protocol) {
@@ -301,7 +293,7 @@ public class GitActivity extends AppCompatActivity {
findViewById(R.id.warn_url).setVisibility(View.GONE);
} else {
- TextView warn_url = (TextView) findViewById(R.id.warn_url);
+ TextView warn_url = findViewById(R.id.warn_url);
if (!server_path.getText().toString().matches("/.*") && !server_port.getText().toString().isEmpty()) {
warn_url.setText(R.string.warn_malformed_url_port);
warn_url.setVisibility(View.VISIBLE);
@@ -342,11 +334,11 @@ public class GitActivity extends AppCompatActivity {
* Splits the information in server_uri into the other fields
*/
private void splitURI() {
- EditText server_uri = (EditText) findViewById(R.id.clone_uri);
- EditText server_url = ((EditText) findViewById(R.id.server_url));
- EditText server_port = ((EditText) findViewById(R.id.server_port));
- EditText server_path = ((EditText) findViewById(R.id.server_path));
- EditText server_user = ((EditText) findViewById(R.id.server_user));
+ EditText server_uri = findViewById(R.id.clone_uri);
+ EditText server_url = findViewById(R.id.server_url);
+ EditText server_port = findViewById(R.id.server_port);
+ EditText server_path = findViewById(R.id.server_path);
+ EditText server_user = findViewById(R.id.server_user);
String uri = server_uri.getText().toString();
Pattern pattern = Pattern.compile("(.+)@([\\w\\d\\.]+):([\\d]+)*(.*)");
@@ -361,7 +353,7 @@ public class GitActivity extends AppCompatActivity {
server_port.setText(matcher.group(3));
server_path.setText(matcher.group(4));
- TextView warn_url = (TextView) findViewById(R.id.warn_url);
+ TextView warn_url = findViewById(R.id.warn_url);
if (!server_path.getText().toString().matches("/.*") && !server_port.getText().toString().isEmpty()) {
warn_url.setText(R.string.warn_malformed_url_port);
warn_url.setVisibility(View.VISIBLE);
@@ -467,8 +459,8 @@ public class GitActivity extends AppCompatActivity {
private void showGitConfig() {
// init the server information
- final EditText git_user_name = ((EditText) findViewById(R.id.git_user_name));
- final EditText git_user_email = ((EditText) findViewById(R.id.git_user_email));
+ final EditText git_user_name = findViewById(R.id.git_user_name);
+ final EditText git_user_email = findViewById(R.id.git_user_email);
git_user_name.setText(settings.getString("git_config_user_name", ""));
git_user_email.setText(settings.getString("git_config_user_email", ""));
@@ -476,7 +468,7 @@ public class GitActivity extends AppCompatActivity {
// git status
Repository repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory(activity.getApplicationContext()));
if (repo != null) {
- final TextView git_commit_hash = (TextView) findViewById(R.id.git_commit_hash);
+ final TextView git_commit_hash = findViewById(R.id.git_commit_hash);
try {
ObjectId objectId = repo.resolve(Constants.HEAD);
Ref ref = repo.getRef("refs/heads/master");
@@ -532,6 +524,7 @@ public class GitActivity extends AppCompatActivity {
GitAsyncTask tasks = new GitAsyncTask(activity, false, true, this);
tasks.execute(new Git(repo).rebase().setOperation(RebaseCommand.Operation.ABORT));
}
+
@Override
public void onSuccess() {
showGitConfig();
@@ -560,36 +553,30 @@ public class GitActivity extends AppCompatActivity {
setMessage(getResources().getString(R.string.dialog_delete_msg) + " " + localDir.toString()).
setCancelable(false).
setPositiveButton(R.string.dialog_delete,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
+ (dialog, id) -> {
+ try {
+ FileUtils.deleteDirectory(localDir);
try {
- FileUtils.deleteDirectory(localDir);
- try {
- new CloneOperation(localDir, activity)
- .setCommand(hostname)
- .executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
- } catch (Exception e) {
- //This is what happens when jgit fails :(
- //TODO Handle the diffent cases of exceptions
- e.printStackTrace();
- new AlertDialog.Builder(GitActivity.this).setMessage(e.getMessage()).show();
- }
- } catch (IOException e) {
- //TODO Handle the exception correctly if we are unable to delete the directory...
+ new CloneOperation(localDir, activity)
+ .setCommand(hostname)
+ .executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
+ } catch (Exception e) {
+ //This is what happens when jgit fails :(
+ //TODO Handle the diffent cases of exceptions
e.printStackTrace();
new AlertDialog.Builder(GitActivity.this).setMessage(e.getMessage()).show();
}
-
- dialog.cancel();
+ } catch (IOException e) {
+ //TODO Handle the exception correctly if we are unable to delete the directory...
+ e.printStackTrace();
+ new AlertDialog.Builder(GitActivity.this).setMessage(e.getMessage()).show();
}
+
+ dialog.cancel();
}
).
setNegativeButton(R.string.dialog_do_not_delete,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- }
+ (dialog, id) -> dialog.cancel()
).
show();
} else {
@@ -626,20 +613,14 @@ public class GitActivity extends AppCompatActivity {
settings.getString("git_remote_location", "").isEmpty())
new AlertDialog.Builder(this)
.setMessage(activity.getResources().getString(R.string.set_information_dialog_text))
- .setPositiveButton(activity.getResources().getString(R.string.dialog_positive), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- Intent intent = new Intent(activity, UserPreference.class);
- startActivityForResult(intent, REQUEST_PULL);
- }
+ .setPositiveButton(activity.getResources().getString(R.string.dialog_positive), (dialogInterface, i) -> {
+ Intent intent = new Intent(activity, UserPreference.class);
+ startActivityForResult(intent, REQUEST_PULL);
})
- .setNegativeButton(activity.getResources().getString(R.string.dialog_negative), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- // do nothing :(
- setResult(RESULT_OK);
- finish();
- }
+ .setNegativeButton(activity.getResources().getString(R.string.dialog_negative), (dialogInterface, i) -> {
+ // do nothing :(
+ setResult(RESULT_OK);
+ finish();
})
.show();
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java b/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java
index 7fe31979..79234a32 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java
@@ -4,10 +4,8 @@ import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.util.Log;
-
import com.zeapo.pwdstore.PasswordStore;
import com.zeapo.pwdstore.R;
-
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.PushCommand;
@@ -52,7 +50,7 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> {
// the previous status will eventually be used to avoid a commit
if (nbChanges == null || nbChanges > 0)
command.call();
- }else if (command instanceof PushCommand) {
+ } else if (command instanceof PushCommand) {
for (final PushResult result : ((PushCommand) command).call()) {
// Code imported (modified) from Gerrit PushOp, license Apache v2
for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java b/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java
index a0da14ab..7f6ecd81 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java
@@ -2,19 +2,17 @@ package com.zeapo.pwdstore.git;
import android.annotation.SuppressLint;
import android.app.Activity;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
-
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.KeyPair;
@@ -23,7 +21,6 @@ import com.zeapo.pwdstore.UserPreference;
import com.zeapo.pwdstore.git.config.GitConfigSessionFactory;
import com.zeapo.pwdstore.git.config.SshConfigSessionFactory;
import com.zeapo.pwdstore.utils.PasswordRepository;
-
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
@@ -109,46 +106,37 @@ public abstract class GitOperation {
new AlertDialog.Builder(callingActivity)
.setMessage(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_text))
.setTitle(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_title))
- .setPositiveButton(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_import), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- try {
- // Ask the UserPreference to provide us with the ssh-key
- // onResult has to be handled by the callingActivity
- Intent intent = new Intent(callingActivity.getApplicationContext(), UserPreference.class);
- intent.putExtra("operation", "get_ssh_key");
- callingActivity.startActivityForResult(intent, GET_SSH_KEY_FROM_CLONE);
- } catch (Exception e) {
- System.out.println("Exception caught :(");
- e.printStackTrace();
- }
+ .setPositiveButton(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_import), (dialog, id) -> {
+ try {
+ // Ask the UserPreference to provide us with the ssh-key
+ // onResult has to be handled by the callingActivity
+ Intent intent = new Intent(callingActivity.getApplicationContext(), UserPreference.class);
+ intent.putExtra("operation", "get_ssh_key");
+ callingActivity.startActivityForResult(intent, GET_SSH_KEY_FROM_CLONE);
+ } catch (Exception e) {
+ System.out.println("Exception caught :(");
+ e.printStackTrace();
}
})
- .setNegativeButton(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_generate), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- try {
- // Duplicated code
- Intent intent = new Intent(callingActivity.getApplicationContext(), UserPreference.class);
- intent.putExtra("operation", "make_ssh_key");
- callingActivity.startActivityForResult(intent, GET_SSH_KEY_FROM_CLONE);
- } catch (Exception e) {
- System.out.println("Exception caught :(");
- e.printStackTrace();
- }
+ .setNegativeButton(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_generate), (dialog, which) -> {
+ try {
+ // Duplicated code
+ Intent intent = new Intent(callingActivity.getApplicationContext(), UserPreference.class);
+ intent.putExtra("operation", "make_ssh_key");
+ callingActivity.startActivityForResult(intent, GET_SSH_KEY_FROM_CLONE);
+ } catch (Exception e) {
+ System.out.println("Exception caught :(");
+ e.printStackTrace();
}
})
- .setNeutralButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- // Finish the blank GitActivity so user doesn't have to press back
- callingActivity.finish();
- }
+ .setNeutralButton(callingActivity.getResources().getString(R.string.dialog_cancel), (dialog, id) -> {
+ // Finish the blank GitActivity so user doesn't have to press back
+ callingActivity.finish();
}).show();
} else {
LayoutInflater layoutInflater = LayoutInflater.from(callingActivity.getApplicationContext());
@SuppressLint("InflateParams") final View dialogView = layoutInflater.inflate(R.layout.git_passphrase_layout, null);
- final EditText passphrase = (EditText) dialogView.findViewById(R.id.sshkey_passphrase);
+ final EditText passphrase = dialogView.findViewById(R.id.sshkey_passphrase);
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(callingActivity.getApplicationContext());
final String sshKeyPassphrase = settings.getString("ssh_key_passphrase", null);
if (showError) {
@@ -172,25 +160,21 @@ public abstract class GitOperation {
.setTitle(callingActivity.getResources().getString(R.string.passphrase_dialog_title))
.setMessage(callingActivity.getResources().getString(R.string.passphrase_dialog_text))
.setView(dialogView)
- .setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- if (keyPair.decrypt(passphrase.getText().toString())) {
- boolean rememberPassphrase = ((CheckBox) dialogView.findViewById(R.id.sshkey_remember_passphrase)).isChecked();
- if (rememberPassphrase) {
- settings.edit().putString("ssh_key_passphrase", passphrase.getText().toString()).apply();
- }
- // Authenticate using the ssh-key and then execute the command
- setAuthentication(sshKey, username, passphrase.getText().toString()).execute();
- } else {
- settings.edit().putString("ssh_key_passphrase", null).apply();
- // call back the method
- executeAfterAuthentication(connectionMode, username, sshKey, true);
+ .setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialog, whichButton) -> {
+ if (keyPair.decrypt(passphrase.getText().toString())) {
+ boolean rememberPassphrase = ((CheckBox) dialogView.findViewById(R.id.sshkey_remember_passphrase)).isChecked();
+ if (rememberPassphrase) {
+ settings.edit().putString("ssh_key_passphrase", passphrase.getText().toString()).apply();
}
+ // Authenticate using the ssh-key and then execute the command
+ setAuthentication(sshKey, username, passphrase.getText().toString()).execute();
+ } else {
+ settings.edit().putString("ssh_key_passphrase", null).apply();
+ // call back the method
+ executeAfterAuthentication(connectionMode, username, sshKey, true);
}
- }).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- // Do nothing.
- }
+ }).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), (dialog, whichButton) -> {
+ // Do nothing.
}).show();
}
} else {
@@ -200,11 +184,8 @@ public abstract class GitOperation {
new AlertDialog.Builder(callingActivity)
.setTitle("Unable to open the ssh-key")
.setMessage("Please check that it was imported.")
- .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
+ .setPositiveButton("Ok", (dialogInterface, i) -> {
- }
}).show();
}
}
@@ -218,16 +199,12 @@ public abstract class GitOperation {
.setTitle(callingActivity.getResources().getString(R.string.passphrase_dialog_title))
.setMessage(callingActivity.getResources().getString(R.string.password_dialog_text))
.setView(password)
- .setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- // authenticate using the user/pwd and then execute the command
- setAuthentication(username, password.getText().toString()).execute();
+ .setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialog, whichButton) -> {
+ // authenticate using the user/pwd and then execute the command
+ setAuthentication(username, password.getText().toString()).execute();
- }
- }).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- // Do nothing.
- }
+ }).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), (dialog, whichButton) -> {
+ // Do nothing.
}).show();
}
}
@@ -239,12 +216,9 @@ public abstract class GitOperation {
new AlertDialog.Builder(callingActivity).
setTitle(callingActivity.getResources().getString(R.string.jgit_error_dialog_title)).
setMessage(callingActivity.getResources().getString(R.string.jgit_error_dialog_text) + errorMessage).
- setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- callingActivity.setResult(Activity.RESULT_CANCELED);
- callingActivity.finish();
- }
+ setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> {
+ callingActivity.setResult(Activity.RESULT_CANCELED);
+ callingActivity.finish();
}).show();
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/PullOperation.java b/app/src/main/java/com/zeapo/pwdstore/git/PullOperation.java
index 1a903aaf..322a6206 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/PullOperation.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/PullOperation.java
@@ -2,13 +2,9 @@ package com.zeapo.pwdstore.git;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.DialogInterface;
-
import com.zeapo.pwdstore.R;
-
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PullCommand;
-import org.eclipse.jgit.merge.MergeStrategy;
import java.io.File;
@@ -26,6 +22,7 @@ public class PullOperation extends GitOperation {
/**
* Sets the command
+ *
* @return the current object
*/
public PullOperation setCommand() {
@@ -52,11 +49,6 @@ public class PullOperation extends GitOperation {
+ callingActivity.getResources().getString(R.string.jgit_error_dialog_text)
+ errorMessage
+ "\nPlease check the FAQ for possible reasons why this error might occur.").
- setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- callingActivity.finish();
- }
- }).show();
+ setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> callingActivity.finish()).show();
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/PushOperation.java b/app/src/main/java/com/zeapo/pwdstore/git/PushOperation.java
index 06eb6bb3..056b7034 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/PushOperation.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/PushOperation.java
@@ -2,10 +2,7 @@ package com.zeapo.pwdstore.git;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.DialogInterface;
-
import com.zeapo.pwdstore.R;
-
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
@@ -25,6 +22,7 @@ public class PushOperation extends GitOperation {
/**
* Sets the command
+ *
* @return the current object
*/
public PushOperation setCommand() {
@@ -49,11 +47,6 @@ public class PushOperation extends GitOperation {
new AlertDialog.Builder(callingActivity).
setTitle(callingActivity.getResources().getString(R.string.jgit_error_dialog_title)).
setMessage(callingActivity.getString(R.string.jgit_error_push_dialog_text) + errorMessage).
- setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- callingActivity.finish();
- }
- }).show();
+ setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> callingActivity.finish()).show();
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java b/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java
index 9dd43cb9..4e7f037d 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java
@@ -2,10 +2,7 @@ package com.zeapo.pwdstore.git;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.DialogInterface;
-
import com.zeapo.pwdstore.R;
-
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
@@ -64,11 +61,6 @@ public class SyncOperation extends GitOperation {
+ callingActivity.getResources().getString(R.string.jgit_error_dialog_text)
+ errorMessage
+ "\nPlease check the FAQ for possible reasons why this error might occur.").
- setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- callingActivity.finish();
- }
- }).show();
+ setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> callingActivity.finish()).show();
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/config/GitConfigSessionFactory.java b/app/src/main/java/com/zeapo/pwdstore/git/config/GitConfigSessionFactory.java
index ab23361e..58762888 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/config/GitConfigSessionFactory.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/config/GitConfigSessionFactory.java
@@ -3,7 +3,6 @@ package com.zeapo.pwdstore.git.config;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
-
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.util.FS;
@@ -15,8 +14,7 @@ public class GitConfigSessionFactory extends JschConfigSessionFactory {
}
@Override
- protected JSch
- getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
+ protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
JSch jsch = super.getJSch(hc, fs);
jsch.removeAllIdentity();
return jsch;
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/config/SshConfigSessionFactory.java b/app/src/main/java/com/zeapo/pwdstore/git/config/SshConfigSessionFactory.java
index b958546e..38c5fb7e 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/config/SshConfigSessionFactory.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/config/SshConfigSessionFactory.java
@@ -4,7 +4,6 @@ import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
-
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt b/app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt
deleted file mode 100644
index 98c3735f..00000000
--- a/app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt
+++ /dev/null
@@ -1,310 +0,0 @@
-package com.zeapo.pwdstore.pwgen
-
-/*
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will Google be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, as long as the origin is not misrepresented.
- */
-
-import android.os.Build
-import android.os.Process
-import android.util.Log
-
-import java.io.ByteArrayOutputStream
-import java.io.DataInputStream
-import java.io.DataOutputStream
-import java.io.File
-import java.io.FileInputStream
-import java.io.FileOutputStream
-import java.io.IOException
-import java.io.OutputStream
-import java.io.UnsupportedEncodingException
-import java.security.NoSuchAlgorithmException
-import java.security.Provider
-import java.security.SecureRandom
-import java.security.SecureRandomSpi
-import java.security.Security
-
-/**
- * Fixes for the output of the default PRNG having low entropy.
- *
- * The fixes need to be applied via [.apply] before any use of Java
- * Cryptography Architecture primitives. A good place to invoke them is in the
- * application's `onCreate`.
- */
-object PRNGFixes {
-
- private const val VERSION_CODE_JELLY_BEAN_MR2 = 18
- private val BUILD_FINGERPRINT_AND_DEVICE_SERIAL = buildFingerprintAndDeviceSerial
-
- private val buildFingerprintAndDeviceSerial: ByteArray
- get() {
- val result = StringBuilder()
- val fingerprint = Build.FINGERPRINT
- if (fingerprint != null) {
- result.append(fingerprint)
- }
- // TODO: Build#SERIAL is deprecated and should be removed or replaced
- val serial = Build.SERIAL
- if (serial != null) {
- result.append(serial)
- }
- try {
- return result.toString().toByteArray(charset("UTF-8"))
- } catch (e: UnsupportedEncodingException) {
- throw RuntimeException("UTF-8 encoding not supported")
- }
- }
-
- /**
- * Applies all fixes.
- *
- * @throws SecurityException if a fix is needed but could not be applied.
- */
- fun apply() {
- applyOpenSSLFix()
- installLinuxPRNGSecureRandom()
- }
-
- /**
- * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
- * fix is not needed.
- *
- * @throws SecurityException if the fix is needed but could not be applied.
- */
- @Throws(SecurityException::class)
- private fun applyOpenSSLFix() {
- if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
- // No need to apply the fix
- return
- }
-
- try {
- // Mix in the device- and invocation-specific seed.
- Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
- .getMethod("RAND_seed", ByteArray::class.java)
- .invoke(null, generateSeed())
-
- // Mix output of Linux PRNG into OpenSSL's PRNG
- val bytesRead = Class.forName(
- "org.apache.harmony.xnet.provider.jsse.NativeCrypto"
- )
- .getMethod("RAND_load_file", String::class.java, Long::class.javaPrimitiveType)
- .invoke(null, "/dev/urandom", 1024) as Int
- if (bytesRead != 1024) {
- throw IOException(
- "Unexpected number of bytes read from Linux PRNG: $bytesRead"
- )
- }
- } catch (e: Exception) {
- throw SecurityException("Failed to seed OpenSSL PRNG", e)
- }
- }
-
- /**
- * Installs a Linux PRNG-backed `SecureRandom` implementation as the
- * default. Does nothing if the implementation is already the default or if
- * there is not need to install the implementation.
- *
- * @throws SecurityException if the fix is needed but could not be applied.
- */
- @Throws(SecurityException::class)
- private fun installLinuxPRNGSecureRandom() {
- if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
- // No need to apply the fix
- return
- }
-
- // Install a Linux PRNG-based SecureRandom implementation as the
- // default, if not yet installed.
- val secureRandomProviders = Security.getProviders("SecureRandom.SHA1PRNG")
- if (secureRandomProviders == null
- || secureRandomProviders.isEmpty()
- || LinuxPRNGSecureRandomProvider::class.java != secureRandomProviders[0].javaClass
- ) {
- Security.insertProviderAt(LinuxPRNGSecureRandomProvider(), 1)
- }
-
- // Assert that new SecureRandom() and
- // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
- // by the Linux PRNG-based SecureRandom implementation.
- val rng1 = SecureRandom()
- if (LinuxPRNGSecureRandomProvider::class.java != rng1.provider.javaClass) {
- throw SecurityException(
- "new SecureRandom() backed by wrong Provider: " + rng1.provider.javaClass
- )
- }
-
- val rng2: SecureRandom
- try {
- rng2 = SecureRandom.getInstance("SHA1PRNG")
- } catch (e: NoSuchAlgorithmException) {
- throw SecurityException("SHA1PRNG not available", e)
- }
-
- if (LinuxPRNGSecureRandomProvider::class.java != rng2.provider.javaClass) {
- throw SecurityException(
- "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
- + " Provider: " + rng2.provider.javaClass
- )
- }
- }
-
- /**
- * `Provider` of `SecureRandom` engines which pass through
- * all requests to the Linux PRNG.
- */
- private class LinuxPRNGSecureRandomProvider :
- Provider("LinuxPRNG", 1.0, "A Linux-specific random number provider that uses" + " /dev/urandom") {
- init {
- // Although /dev/urandom is not a SHA-1 PRNG, some apps
- // explicitly request a SHA1PRNG SecureRandom and we thus need to
- // prevent them from getting the default implementation whose output
- // may have low entropy.
- put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom::class.java.name)
- put("SecureRandom.SHA1PRNG ImplementedIn", "Software")
- }
- }
-
- /**
- * [SecureRandomSpi] which passes all requests to the Linux PRNG
- * (`/dev/urandom`).
- */
- class LinuxPRNGSecureRandom : SecureRandomSpi() {
-
- /**
- * Whether this engine instance has been seeded. This is needed because
- * each instance needs to seed itself if the client does not explicitly
- * seed it.
- */
- private var mSeeded: Boolean = false
-
- private// NOTE: Consider inserting a BufferedInputStream between
- // DataInputStream and FileInputStream if you need higher
- // PRNG output performance and can live with future PRNG
- // output being pulled into this process prematurely.
- val urandomInputStream: DataInputStream
- get() = synchronized(sLock) {
- if (sUrandomIn == null) {
- try {
- sUrandomIn = DataInputStream(
- FileInputStream(URANDOM_FILE)
- )
- } catch (e: IOException) {
- throw SecurityException(
- "Failed to open "
- + URANDOM_FILE + " for reading", e
- )
- }
- }
- return sUrandomIn as DataInputStream
- }
-
- private val urandomOutputStream: OutputStream
- @Throws(IOException::class)
- get() = synchronized(sLock) {
- if (sUrandomOut == null) {
- sUrandomOut = FileOutputStream(URANDOM_FILE)
- }
- return sUrandomOut as OutputStream
- }
-
- @Synchronized
- override fun engineSetSeed(bytes: ByteArray) {
- try {
- val out: OutputStream = urandomOutputStream
- out.write(bytes)
- out.flush()
- } catch (e: IOException) {
- // On a small fraction of devices /dev/urandom is not writable.
- // Log and ignore.
- Log.w(
- PRNGFixes::class.java.simpleName,
- "Failed to mix seed into $URANDOM_FILE"
- )
- } finally {
- mSeeded = true
- }
- }
-
- @Synchronized
- override fun engineNextBytes(bytes: ByteArray) {
- if (!mSeeded) {
- // Mix in the device- and invocation-specific seed.
- engineSetSeed(generateSeed())
- }
-
- try {
- val `in`: DataInputStream = urandomInputStream
- synchronized(`in`) {
- `in`.readFully(bytes)
- }
- } catch (e: IOException) {
- throw SecurityException(
- "Failed to read from $URANDOM_FILE", e
- )
- }
- }
-
- override fun engineGenerateSeed(size: Int): ByteArray {
- val seed = ByteArray(size)
- engineNextBytes(seed)
- return seed
- }
-
- companion object {
-
- /*
- * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
- * are passed through to the Linux PRNG (/dev/urandom). Instances of
- * this class seed themselves by mixing in the current time, PID, UID,
- * build fingerprint, and hardware serial number (where available) into
- * Linux PRNG.
- *
- * Concurrency: Read requests to the underlying Linux PRNG are
- * serialized (on sLock) to ensure that multiple threads do not get
- * duplicated PRNG output.
- */
-
- private val URANDOM_FILE = File("/dev/urandom")
-
- private val sLock = Any()
-
- /**
- * Input stream for reading from Linux PRNG or `null` if not yet
- * opened.
- */
- private var sUrandomIn: DataInputStream? = null
-
- /**
- * Output stream for writing to Linux PRNG or `null` if not yet
- * opened.
- */
- private var sUrandomOut: OutputStream? = null
- }
- }
-
- /**
- * Generates a device- and invocation-specific seed to be mixed into the
- * Linux PRNG.
- */
- private fun generateSeed(): ByteArray {
- try {
- val seedBuffer = ByteArrayOutputStream()
- val seedBufferOut = DataOutputStream(seedBuffer)
- seedBufferOut.writeLong(System.currentTimeMillis())
- seedBufferOut.writeLong(System.nanoTime())
- seedBufferOut.writeInt(Process.myPid())
- seedBufferOut.writeInt(Process.myUid())
- seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL)
- seedBufferOut.close()
- return seedBuffer.toByteArray()
- } catch (e: IOException) {
- throw SecurityException("Failed to generate seed", e)
- }
- }
-}
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt b/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt
index 0374236c..3a7dcc27 100644
--- a/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt
@@ -1,26 +1,25 @@
package com.zeapo.pwdstore.pwgen
import android.content.Context
-import android.content.SharedPreferences
import java.util.ArrayList
object PasswordGenerator {
- internal val DIGITS = 0x0001
- internal val UPPERS = 0x0002
- internal val SYMBOLS = 0x0004
- internal val AMBIGUOUS = 0x0008
- internal val NO_VOWELS = 0x0010
+ internal const val DIGITS = 0x0001
+ internal const val UPPERS = 0x0002
+ internal const val SYMBOLS = 0x0004
+ internal const val AMBIGUOUS = 0x0008
+ internal const val NO_VOWELS = 0x0010
- internal val DIGITS_STR = "0123456789"
- internal val UPPERS_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- internal val LOWERS_STR = "abcdefghijklmnopqrstuvwxyz"
- internal val SYMBOLS_STR = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
- internal val AMBIGUOUS_STR = "B8G6I1l0OQDS5Z2"
- internal val VOWELS_STR = "01aeiouyAEIOUY"
+ internal const val DIGITS_STR = "0123456789"
+ internal const val UPPERS_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ internal const val LOWERS_STR = "abcdefghijklmnopqrstuvwxyz"
+ internal const val SYMBOLS_STR = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
+ internal const val AMBIGUOUS_STR = "B8G6I1l0OQDS5Z2"
+ internal const val VOWELS_STR = "01aeiouyAEIOUY"
// No a, c, n, h, H, C, 1, N
- private val pwOptions = "0ABsvy"
+ private const val pwOptions = "0ABsvy"
/**
* Sets password generation preferences.
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java
index cabc0dcf..c108cb52 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/EntryRecyclerAdapter.java
@@ -3,15 +3,14 @@ package com.zeapo.pwdstore.utils;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Color;
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
-import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
import com.zeapo.pwdstore.R;
import java.util.ArrayList;
@@ -19,9 +18,9 @@ import java.util.Set;
import java.util.TreeSet;
public abstract class EntryRecyclerAdapter extends RecyclerView.Adapter<EntryRecyclerAdapter.ViewHolder> {
+ final Set<Integer> selectedItems = new TreeSet<>();
private final Activity activity;
private final ArrayList<PasswordItem> values;
- final Set<Integer> selectedItems = new TreeSet<>();
EntryRecyclerAdapter(Activity activity, ArrayList<PasswordItem> values) {
this.activity = activity;
@@ -85,18 +84,13 @@ public abstract class EntryRecyclerAdapter extends RecyclerView.Adapter<EntryRec
@NonNull
View.OnLongClickListener getOnLongClickListener(ViewHolder holder, PasswordItem pass) {
- return new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- return false;
- }
- };
+ return v -> false;
}
// Replace the contents of a view (invoked by the layout manager)
@SuppressLint("SetTextI18n")
@Override
- public void onBindViewHolder(final ViewHolder holder, int position) {
+ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final PasswordItem pass = getValues().get(position);
holder.name.setText(pass.toString());
if (pass.getType() == PasswordItem.TYPE_CATEGORY) {
@@ -127,6 +121,17 @@ public abstract class EntryRecyclerAdapter extends RecyclerView.Adapter<EntryRec
@NonNull
protected abstract View.OnClickListener getOnClickListener(ViewHolder holder, PasswordItem pass);
+ // Create new views (invoked by the layout manager)
+ @Override
+ @NonNull
+ public PasswordRecyclerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+ int viewType) {
+ // create a new view
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.password_row_layout, parent, false);
+ return new ViewHolder(v);
+ }
+
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
@@ -140,19 +145,9 @@ public abstract class EntryRecyclerAdapter extends RecyclerView.Adapter<EntryRec
ViewHolder(View v) {
super(v);
view = v;
- name = (TextView) view.findViewById(R.id.label);
- type = (TextView) view.findViewById(R.id.type);
- typeImage = (ImageView) view.findViewById(R.id.type_image);
+ name = view.findViewById(R.id.label);
+ type = view.findViewById(R.id.type);
+ typeImage = view.findViewById(R.id.type_image);
}
}
-
- // Create new views (invoked by the layout manager)
- @Override
- public PasswordRecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- // create a new view
- View v = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.password_row_layout, parent, false);
- return new ViewHolder(v);
- }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java
index d155802f..f6a29113 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/FolderRecyclerAdapter.java
@@ -1,8 +1,7 @@
package com.zeapo.pwdstore.utils;
-import androidx.annotation.NonNull;
import android.view.View;
-
+import androidx.annotation.NonNull;
import com.zeapo.pwdstore.SelectFolderActivity;
import com.zeapo.pwdstore.SelectFolderFragment;
@@ -19,12 +18,9 @@ public class FolderRecyclerAdapter extends EntryRecyclerAdapter {
@NonNull
protected View.OnClickListener getOnClickListener(final ViewHolder holder, final PasswordItem pass) {
- return new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- listener.onFragmentInteraction(pass);
- notifyItemChanged(holder.getAdapterPosition());
- }
+ return v -> {
+ listener.onFragmentInteraction(pass);
+ notifyItemChanged(holder.getAdapterPosition());
};
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/Otp.java b/app/src/main/java/com/zeapo/pwdstore/utils/Otp.java
index 44e2aa64..35e773e4 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/Otp.java
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/Otp.java
@@ -1,18 +1,16 @@
package com.zeapo.pwdstore.utils;
import android.util.Log;
-
import org.apache.commons.codec.binary.Base32;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
public class Otp {
public static final int TIME_WINDOW = 30;
@@ -27,7 +25,7 @@ public class Otp {
public static String calculateCode(String secret, long counter) {
SecretKeySpec signingKey = new SecretKeySpec(BASE_32.decode(secret), ALGORITHM);
- Mac mac = null;
+ Mac mac;
try {
mac = Mac.getInstance(ALGORITHM);
mac.init(signingKey);
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java
index 5c2231a5..b79f2130 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java
@@ -1,8 +1,7 @@
package com.zeapo.pwdstore.utils;
-import com.zeapo.pwdstore.crypto.PgpActivity;
-
import androidx.annotation.NonNull;
+import com.zeapo.pwdstore.crypto.PgpActivity;
import java.io.File;
@@ -18,8 +17,9 @@ public class PasswordItem implements Comparable {
private final String fullPathToParent;
private final String longName;
- /** Create a password item
- *
+ /**
+ * Create a password item
+ * <p>
* Make it protected so that we use a builder
*/
private PasswordItem(String name, PasswordItem parent, char type, File file, File rootDir) {
@@ -33,35 +33,39 @@ public class PasswordItem implements Comparable {
longName = PgpActivity.getLongName(fullPathToParent, rootDir.getAbsolutePath(), toString());
}
- /** Create a new Category item
+ /**
+ * Create a new Category item
*/
public static PasswordItem newCategory(String name, File file, PasswordItem parent, File rootDir) {
return new PasswordItem(name, parent, TYPE_CATEGORY, file, rootDir);
}
- /** Create a new parentless category item
+ /**
+ * Create a new parentless category item
*/
public static PasswordItem newCategory(String name, File file, File rootDir) {
return new PasswordItem(name, null, TYPE_CATEGORY, file, rootDir);
}
- /** Create a new password item
+ /**
+ * Create a new password item
*/
- public static PasswordItem newPassword(String name, File file, PasswordItem parent, File rootDir) {
+ public static PasswordItem newPassword(String name, File file, PasswordItem parent, File rootDir) {
return new PasswordItem(name, parent, TYPE_PASSWORD, file, rootDir);
}
- /** Create a new parentless password item
+ /**
+ * Create a new parentless password item
*/
public static PasswordItem newPassword(String name, File file, File rootDir) {
return new PasswordItem(name, null, TYPE_PASSWORD, file, rootDir);
}
- public char getType(){
+ public char getType() {
return this.type;
}
- String getName(){
+ String getName() {
return this.name;
}
@@ -81,8 +85,9 @@ public class PasswordItem implements Comparable {
return longName;
}
+ @NonNull
@Override
- public String toString(){
+ public String toString() {
return this.getName().replace(".gpg", "");
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java
index 751d8559..83244a3f 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRecyclerAdapter.java
@@ -1,11 +1,10 @@
package com.zeapo.pwdstore.utils;
-import androidx.annotation.NonNull;
-import androidx.appcompat.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-
+import androidx.annotation.NonNull;
+import androidx.appcompat.view.ActionMode;
import com.zeapo.pwdstore.PasswordFragment;
import com.zeapo.pwdstore.PasswordStore;
import com.zeapo.pwdstore.R;
@@ -19,63 +18,6 @@ public class PasswordRecyclerAdapter extends EntryRecyclerAdapter {
private final PasswordFragment.OnFragmentInteractionListener listener;
public ActionMode mActionMode;
private Boolean canEdit;
-
- // Provide a suitable constructor (depends on the kind of dataset)
- public PasswordRecyclerAdapter(PasswordStore activity, PasswordFragment.OnFragmentInteractionListener listener, ArrayList<PasswordItem> values) {
- super(activity, values);
- this.activity = activity;
- this.listener = listener;
- }
-
- @Override
- @NonNull
- protected View.OnLongClickListener getOnLongClickListener(final ViewHolder holder, final PasswordItem pass) {
- return new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (mActionMode != null) {
- return false;
- }
- toggleSelection(holder.getAdapterPosition());
- canEdit = pass.getType() == PasswordItem.TYPE_PASSWORD;
- // Start the CAB using the ActionMode.Callback
- mActionMode = activity.startSupportActionMode(mActionModeCallback);
- mActionMode.setTitle("" + selectedItems.size());
- mActionMode.invalidate();
- notifyItemChanged(holder.getAdapterPosition());
- return true;
- }
- };
- }
-
- @Override
- @NonNull
- protected View.OnClickListener getOnClickListener(final ViewHolder holder, final PasswordItem pass) {
- return new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mActionMode != null) {
- toggleSelection(holder.getAdapterPosition());
- mActionMode.setTitle("" + selectedItems.size());
- if (selectedItems.isEmpty()) {
- mActionMode.finish();
- } else if (selectedItems.size() == 1 && !canEdit) {
- if (getValues().get(selectedItems.iterator().next()).getType() == PasswordItem.TYPE_PASSWORD) {
- canEdit = true;
- mActionMode.invalidate();
- }
- } else if (selectedItems.size() >= 1 && canEdit) {
- canEdit = false;
- mActionMode.invalidate();
- }
- } else {
- listener.onFragmentInteraction(pass);
- }
- notifyItemChanged(holder.getAdapterPosition());
- }
- };
- }
-
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
@@ -136,4 +78,54 @@ public class PasswordRecyclerAdapter extends EntryRecyclerAdapter {
activity.findViewById(R.id.fab).setVisibility(View.VISIBLE);
}
};
+
+ // Provide a suitable constructor (depends on the kind of dataset)
+ public PasswordRecyclerAdapter(PasswordStore activity, PasswordFragment.OnFragmentInteractionListener listener, ArrayList<PasswordItem> values) {
+ super(activity, values);
+ this.activity = activity;
+ this.listener = listener;
+ }
+
+ @Override
+ @NonNull
+ protected View.OnLongClickListener getOnLongClickListener(final ViewHolder holder, final PasswordItem pass) {
+ return v -> {
+ if (mActionMode != null) {
+ return false;
+ }
+ toggleSelection(holder.getAdapterPosition());
+ canEdit = pass.getType() == PasswordItem.TYPE_PASSWORD;
+ // Start the CAB using the ActionMode.Callback
+ mActionMode = activity.startSupportActionMode(mActionModeCallback);
+ mActionMode.setTitle("" + selectedItems.size());
+ mActionMode.invalidate();
+ notifyItemChanged(holder.getAdapterPosition());
+ return true;
+ };
+ }
+
+ @Override
+ @NonNull
+ protected View.OnClickListener getOnClickListener(final ViewHolder holder, final PasswordItem pass) {
+ return v -> {
+ if (mActionMode != null) {
+ toggleSelection(holder.getAdapterPosition());
+ mActionMode.setTitle("" + selectedItems.size());
+ if (selectedItems.isEmpty()) {
+ mActionMode.finish();
+ } else if (selectedItems.size() == 1 && !canEdit) {
+ if (getValues().get(selectedItems.iterator().next()).getType() == PasswordItem.TYPE_PASSWORD) {
+ canEdit = true;
+ mActionMode.invalidate();
+ }
+ } else if (selectedItems.size() >= 1 && canEdit) {
+ canEdit = false;
+ mActionMode.invalidate();
+ }
+ } else {
+ listener.onFragmentInteraction(pass);
+ }
+ notifyItemChanged(holder.getAdapterPosition());
+ };
+ }
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java
index fdb53ac4..e79acac8 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java
@@ -4,7 +4,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
-
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
@@ -269,9 +268,7 @@ public class PasswordRepository {
return (p2.getType() + p1.getName())
.compareToIgnoreCase(p1.getType() + p2.getName());
}
- })
-
- ;
+ });
private Comparator<PasswordItem> comparator;