Merge branch 'upstream' into webview

Conflicts:
	app/build.gradle
This commit is contained in:
Matthew Wong
2015-12-31 06:24:05 -05:00
11 changed files with 263 additions and 94 deletions

View File

@@ -4,13 +4,13 @@ apply plugin: 'eclipse'
android { android {
compileSdkVersion 23 compileSdkVersion 23
buildToolsVersion "23.0.2" buildToolsVersion '23.0.2'
defaultConfig { defaultConfig {
applicationId "com.zeapo.pwdstore" applicationId "com.zeapo.pwdstore"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 23 targetSdkVersion 23
versionCode 55 versionCode 58
versionName "1.2.0.35" versionName "1.2.0.38"
} }
compileOptions { compileOptions {
@@ -25,6 +25,8 @@ android {
packagingOptions { packagingOptions {
exclude '.readme' exclude '.readme'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
} }
// //
@@ -61,13 +63,13 @@ dependencies {
compile 'com.android.support:cardview-v7:23.1.1' compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.android.support:design:23.1.1' compile 'com.android.support:design:23.1.1'
compile 'org.sufficientlysecure:openpgp-api:9.0' compile 'org.sufficientlysecure:openpgp-api:9.0'
compile 'com.nononsenseapps:filepicker:2.4.2'
compile ('org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r') { compile ('org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r') {
exclude group: 'org.apache.httpcomponents', module: 'httpclient' exclude group: 'org.apache.httpcomponents', module: 'httpclient'
} }
compile 'com.jcraft:jsch:0.1.53' compile 'com.jcraft:jsch:0.1.53'
compile 'org.apache.commons:commons-io:1.3.2' compile 'org.apache.commons:commons-io:1.3.2'
compile 'com.jayway.android.robotium:robotium-solo:5.3.1' compile 'com.jayway.android.robotium:robotium-solo:5.3.1'
compile 'net.rdrei.android.dirchooser:library:2.1@aar'
compile group: 'com.google.guava', name: 'guava', version: '18.0' compile group: 'com.google.guava', name: 'guava', version: '18.0'
} }
tasks.findAll { // make all tasks whose name starts with 'assemble'... tasks.findAll { // make all tasks whose name starts with 'assemble'...

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zeapo.pwdstore"> package="com.zeapo.pwdstore">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@@ -70,7 +70,15 @@
android:value="com.zeapo.pwdstore.PasswordStore" /> android:value="com.zeapo.pwdstore.PasswordStore" />
</activity> </activity>
<activity android:name="net.rdrei.android.dirchooser.DirectoryChooserActivity" /> <activity
android:name="com.nononsenseapps.filepicker.FilePickerActivity"
android:label="@string/app_name"
android:theme="@style/FilePickerTheme">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application> </application>
</manifest> </manifest>

View File

@@ -1,13 +1,19 @@
package com.zeapo.pwdstore; package com.zeapo.pwdstore;
import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
@@ -16,6 +22,7 @@ import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.TextView;
import com.zeapo.pwdstore.crypto.PgpHandler; import com.zeapo.pwdstore.crypto.PgpHandler;
import com.zeapo.pwdstore.git.GitActivity; import com.zeapo.pwdstore.git.GitActivity;
@@ -47,19 +54,76 @@ public class PasswordStore extends AppCompatActivity {
private final static int NEW_REPO_BUTTON = 402; private final static int NEW_REPO_BUTTON = 402;
private final static int HOME = 403; private final static int HOME = 403;
private final static int REQUEST_EXTERNAL_STORAGE = 50;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pwdstore);
settings = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); settings = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext());
activity = this; activity = this;
PRNGFixes.apply(); PRNGFixes.apply();
// If user opens app with permission granted then revokes and returns,
// prevent attempt to create password list fragment
if (savedInstanceState != null && (!settings.getBoolean("git_external", false)
|| ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
savedInstanceState = null;
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pwdstore);
} }
@Override @Override
public void onResume(){ public void onResume(){
super.onResume(); super.onResume();
checkLocalRepository(); // do not attempt to checkLocalRepository() if no storage permission: immediate crash
if (settings.getBoolean("git_external", false)) {
if (ContextCompat.checkSelfPermission(activity,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
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);
}
});
snack.show();
View view = snack.getView();
TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
tv.setTextColor(Color.WHITE);
tv.setMaxLines(10);
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_EXTERNAL_STORAGE);
}
} else {
checkLocalRepository();
}
} else {
checkLocalRepository();
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_EXTERNAL_STORAGE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkLocalRepository();
}
}
}
} }
@Override @Override
@@ -495,33 +559,9 @@ public class PasswordStore extends AppCompatActivity {
PasswordRepository.closeRepository(); PasswordRepository.closeRepository();
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setTitle("Repositiory location") .setTitle("Repository location")
.setMessage("Select where to create or clone your password repository.") .setMessage("Select where to create or clone your password repository.")
.setPositiveButton("External", new DialogInterface.OnClickListener() { .setPositiveButton("Hidden (preferred)", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
settings.edit().putBoolean("git_external", true).apply();
if (settings.getString("git_external_repo", null) == null) {
Intent intent = new Intent(activity, UserPreference.class);
intent.putExtra("operation", "git_external");
startActivityForResult(intent, operation);
} else {
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("Internal", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) { public void onClick(DialogInterface dialog, int whichButton) {
settings.edit().putBoolean("git_external", false).apply(); settings.edit().putBoolean("git_external", false).apply();
@@ -539,6 +579,46 @@ public class PasswordStore extends AppCompatActivity {
} }
} }
}) })
.setNegativeButton("SD-Card", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
settings.edit().putBoolean("git_external", true).apply();
if (settings.getString("git_external_repo", null) == null) {
Intent intent = new Intent(activity, UserPreference.class);
intent.putExtra("operation", "git_external");
startActivityForResult(intent, operation);
} else {
new AlertDialog.Builder(activity).
setTitle("Directory already selected").
setMessage("Do you want to use \"" + settings.getString("git_external_repo", null) + "\"?").
setPositiveButton("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("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();
}
}
})
.show(); .show();
} }

View File

@@ -1,6 +1,7 @@
package com.zeapo.pwdstore; package com.zeapo.pwdstore;
import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
import android.app.DialogFragment; import android.app.DialogFragment;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@@ -8,6 +9,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
@@ -15,7 +17,6 @@ import android.preference.PreferenceManager;
import android.provider.Settings; import android.provider.Settings;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.text.SpannableStringBuilder;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.widget.Toast; import android.widget.Toast;
@@ -23,13 +24,12 @@ import android.widget.Toast;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.nononsenseapps.filepicker.FilePickerActivity;
import com.zeapo.pwdstore.autofill.AutofillPreferenceActivity; import com.zeapo.pwdstore.autofill.AutofillPreferenceActivity;
import com.zeapo.pwdstore.crypto.PgpHandler; import com.zeapo.pwdstore.crypto.PgpHandler;
import com.zeapo.pwdstore.git.GitActivity; import com.zeapo.pwdstore.git.GitActivity;
import com.zeapo.pwdstore.utils.PasswordRepository; import com.zeapo.pwdstore.utils.PasswordRepository;
import net.rdrei.android.dirchooser.DirectoryChooserActivity;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.openintents.openpgp.util.OpenPgpKeyPreference; import org.openintents.openpgp.util.OpenPgpKeyPreference;
@@ -124,7 +124,8 @@ public class UserPreference extends AppCompatActivity {
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
new AlertDialog.Builder(callingActivity). new AlertDialog.Builder(callingActivity).
setTitle(R.string.pref_dialog_delete_title). setTitle(R.string.pref_dialog_delete_title).
setMessage(R.string.pref_dialog_delete_msg). setMessage(getResources().getString(R.string.dialog_delete_msg)
+ " \n" + PasswordRepository.getWorkTree().toString()).
setCancelable(false). setCancelable(false).
setPositiveButton(R.string.dialog_delete, new DialogInterface.OnClickListener() { setPositiveButton(R.string.dialog_delete, new DialogInterface.OnClickListener() {
@Override @Override
@@ -230,6 +231,7 @@ public class UserPreference extends AppCompatActivity {
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
final SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences(); final SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences();
findPreference("pref_select_external").setSummary(getPreferenceManager().getSharedPreferences().getString("git_external_repo", "No external repository selected"));
findPreference("ssh_see_key").setEnabled(sharedPreferences.getBoolean("use_generated_key", false)); findPreference("ssh_see_key").setEnabled(sharedPreferences.getBoolean("use_generated_key", false));
// see if the autofill service is enabled and check the preference accordingly // see if the autofill service is enabled and check the preference accordingly
@@ -264,11 +266,32 @@ public class UserPreference extends AppCompatActivity {
} }
public void selectExternalGitRepository() { public void selectExternalGitRepository() {
Intent intent = new Intent(this, DirectoryChooserActivity.class); final Activity activity = this;
intent.putExtra(DirectoryChooserActivity.EXTRA_NEW_DIR_NAME, new AlertDialog.Builder(this).
"passwordstore"); setTitle("Choose where to store the passwords").
setMessage("You must select a directory where to store your passwords. If you want " +
"to store your passwords within the hidden storage of the application, " +
"cancel this dialog and disable the \"External Repository\" option.").
setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// This always works
Intent i = new Intent(activity.getApplicationContext(), FilePickerActivity.class);
// 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().getPath());
startActivityForResult(i, SELECT_GIT_DIRECTORY);
}
}).
setNegativeButton(R.string.dialog_cancel, null).show();
startActivityForResult(intent, SELECT_GIT_DIRECTORY);
} }
@Override @Override
@@ -344,6 +367,11 @@ public class UserPreference extends AppCompatActivity {
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("use_generated_key", false); editor.putBoolean("use_generated_key", false);
editor.apply(); editor.apply();
//delete the public key from generation
File file = new File(getFilesDir() + "/.ssh_key.pub");
file.delete();
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();
} catch (IOException e) { } catch (IOException e) {
@@ -371,17 +399,53 @@ public class UserPreference extends AppCompatActivity {
} }
} }
break; break;
case SELECT_GIT_DIRECTORY: {
final Uri uri = data.getData();
if (uri.getPath().equals(Environment.getExternalStorageDirectory().getPath())) {
// the user wants to use the root of the sdcard as a store...
new 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 be deleted").
setPositiveButton("Remove everything", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
.edit()
.putString("git_external_repo", uri.getPath())
.apply();
}
}).
setNegativeButton(R.string.dialog_cancel, null).show();
} else if (new File(uri.getPath()).listFiles().length != 0) {
new AlertDialog.Builder(this).
setTitle("Directory not empty").
setMessage("You have selected a non-empty directory for the store. " +
"This is extremely dangerous and you will lose your data " +
"as its content will be deleted").
setPositiveButton("Remove everything", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
.edit()
.putString("git_external_repo", uri.getPath())
.apply();
}
}).
setNegativeButton(R.string.dialog_cancel, null).show();
} else {
PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
.edit()
.putString("git_external_repo", uri.getPath())
.apply();
}
}
break;
default: default:
break; break;
} }
} }
// why do they have to use a different resultCode than OK :/
if (requestCode == SELECT_GIT_DIRECTORY && resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
.edit()
.putString("git_external_repo", data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR))
.apply();
}
} }
} }

View File

@@ -560,6 +560,7 @@ public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConne
} }
// TODO (low priority but still...) android M potential permissions crashes
@Override @Override
public void onBound(IOpenPgpService2 service) { public void onBound(IOpenPgpService2 service) {
Log.i("PGP", "ISBOUND!!"); Log.i("PGP", "ISBOUND!!");

View File

@@ -45,7 +45,6 @@ public class GitActivity extends AppCompatActivity {
private File localDir; private File localDir;
private String hostname; private String hostname;
private String username;
private String port; private String port;
private SharedPreferences settings; private SharedPreferences settings;
@@ -404,7 +403,7 @@ public class GitActivity extends AppCompatActivity {
/** /**
* Saves the configuration found in the form * Saves the configuration found in the form
*/ */
private void saveConfiguration() { private boolean saveConfiguration() {
// remember the settings // remember the settings
SharedPreferences.Editor editor = settings.edit(); SharedPreferences.Editor editor = settings.edit();
@@ -416,11 +415,39 @@ public class GitActivity extends AppCompatActivity {
editor.putString("git_remote_port", ((EditText) findViewById(R.id.server_port)).getText().toString()); editor.putString("git_remote_port", ((EditText) findViewById(R.id.server_port)).getText().toString());
editor.putString("git_remote_uri", ((EditText) findViewById(R.id.clone_uri)).getText().toString()); editor.putString("git_remote_uri", ((EditText) findViewById(R.id.clone_uri)).getText().toString());
// 'save' hostname variable for use by addRemote() either here or later
// in syncRepository()
hostname = ((EditText) findViewById(R.id.clone_uri)).getText().toString();
port = ((EditText) findViewById(R.id.server_port)).getText().toString();
// don't ask the user, take off the protocol that he puts in
hostname = hostname.replaceFirst("^.+://", "");
((TextView) findViewById(R.id.clone_uri)).setText(hostname);
if (!protocol.equals("ssh://")) {
hostname = protocol + hostname;
} else {
// if the port is explicitly given, jgit requires the ssh://
if (!port.isEmpty())
hostname = protocol + hostname;
// did he forget the username?
if (!hostname.matches("^.+@.+")) {
new AlertDialog.Builder(this).
setMessage(activity.getResources().getString(R.string.forget_username_dialog_text)).
setPositiveButton(activity.getResources().getString(R.string.dialog_oops), null).
show();
return false;
}
}
if (PasswordRepository.isInitialized()) { if (PasswordRepository.isInitialized()) {
PasswordRepository.addRemote("origin", ((EditText) findViewById(R.id.clone_uri)).getText().toString(), true); // don't just use the clone_uri text, need to use hostname which has
// had the proper protocol prepended
PasswordRepository.addRemote("origin", hostname, true);
} }
editor.apply(); editor.apply();
return true;
} }
/** /**
@@ -429,7 +456,8 @@ public class GitActivity extends AppCompatActivity {
* @param view * @param view
*/ */
public void saveConfiguration(View view) { public void saveConfiguration(View view) {
saveConfiguration(); if (!saveConfiguration())
return;
finish(); finish();
} }
@@ -443,45 +471,14 @@ public class GitActivity extends AppCompatActivity {
PasswordRepository.initialize(this); PasswordRepository.initialize(this);
} }
localDir = PasswordRepository.getWorkTree(); localDir = PasswordRepository.getWorkTree();
hostname = ((EditText) findViewById(R.id.clone_uri)).getText().toString();
port = ((EditText) findViewById(R.id.server_port)).getText().toString();
// don't ask the user, take off the protocol that he puts in
hostname = hostname.replaceFirst("^.+://", "");
((TextView) findViewById(R.id.clone_uri)).setText(hostname);
// now cheat a little and prepend the real protocol if (!saveConfiguration())
// jGit does not accept a ssh:// but requires https:// return;
if (!protocol.equals("ssh://")) {
hostname = protocol + hostname;
} else {
// if the port is explicitly given, jgit requires the ssh://
if (!port.isEmpty())
hostname = protocol + hostname;
// did he forget the username?
if (!hostname.matches("^.+@.+")) {
new AlertDialog.Builder(this).
setMessage(activity.getResources().getString(R.string.forget_username_dialog_text)).
setPositiveButton(activity.getResources().getString(R.string.dialog_oops), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
}).
show();
return;
}
username = hostname.split("@")[0];
}
saveConfiguration();
if (localDir.exists() && localDir.listFiles().length != 0) { if (localDir.exists() && localDir.listFiles().length != 0) {
new AlertDialog.Builder(this). new AlertDialog.Builder(this).
setTitle(R.string.dialog_delete_title). setTitle(R.string.dialog_delete_title).
setMessage(R.string.dialog_delete_msg). setMessage(getResources().getString(R.string.dialog_delete_msg) + " " + localDir.toString()).
setCancelable(false). setCancelable(false).
setPositiveButton(R.string.dialog_delete, setPositiveButton(R.string.dialog_delete,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {

View File

@@ -9,7 +9,7 @@
<string name="action_settings">Nastavení</string> <string name="action_settings">Nastavení</string>
<string name="hello_world">Hello world!</string> <string name="hello_world">Hello world!</string>
<string name="dialog_delete_title">Adresář již existuje</string> <string name="dialog_delete_title">Adresář již existuje</string>
<string name="dialog_delete_msg">Cílový adresář již existuje. Aktuální verze podporuje pouze jedno úložiště. Opravdu smazat aktuální adresář úložiště hesel?</string> <string name="dialog_delete_msg">Cílový adresář již existuje. Aktuální verze podporuje pouze jedno úložiště. Opravdu smazat aktuální adresář úložiště hesel:</string>
<string name="dialog_delete">Smazat adresář</string> <string name="dialog_delete">Smazat adresář</string>
<string name="dialog_do_not_delete">Zrušit</string> <string name="dialog_do_not_delete">Zrušit</string>
<string name="title_activity_git_clone">Informace repozitáře</string> <string name="title_activity_git_clone">Informace repozitáře</string>

View File

@@ -9,7 +9,7 @@
<string name="action_settings">Settings</string> <string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string> <string name="hello_world">Hello world!</string>
<string name="dialog_delete_title">Directory already exist</string> <string name="dialog_delete_title">Directory already exist</string>
<string name="dialog_delete_msg">Target directory already exist. Current version support only a single store. Do you want to delete the current password store directory?</string> <string name="dialog_delete_msg">Target directory already exist. Current version support only a single store. Do you want to delete the current password store directory:</string>
<string name="dialog_delete">Delete directory</string> <string name="dialog_delete">Delete directory</string>
<string name="dialog_do_not_delete">Cancel</string> <string name="dialog_do_not_delete">Cancel</string>
<string name="title_activity_git_clone">Repository information</string> <string name="title_activity_git_clone">Repository information</string>

View File

@@ -13,4 +13,21 @@
<style name="ActionMode" parent="@style/Widget.AppCompat.ActionMode"> <style name="ActionMode" parent="@style/Widget.AppCompat.ActionMode">
<item name="background">@color/blue_grey_700</item> <item name="background">@color/blue_grey_700</item>
</style> </style>
<!-- You can also inherit from NNF_BaseTheme.Light -->
<style name="FilePickerTheme" parent="NNF_BaseTheme">
<!-- Set these to match your theme -->
<item name="colorPrimary">@color/blue_grey_500</item>
<item name="colorPrimaryDark">@color/blue_grey_700</item>
<item name="colorAccent">@color/teal_A700</item>
<!-- Need to set this also to style create folder dialog -->
<item name="alertDialogTheme">@style/FilePickerAlertDialogTheme</item>
</style>
<style name="FilePickerAlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
<item name="colorPrimary">@color/blue_grey_500</item>
<item name="colorPrimaryDark">@color/blue_grey_700</item>
<item name="colorAccent">@color/teal_A700</item>
</style>
</resources> </resources>

View File

@@ -6,7 +6,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:1.3.0' classpath 'com.android.tools.build:gradle:1.5.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

View File

@@ -1,6 +1,6 @@
#Thu Dec 04 19:46:18 CET 2014 #Wed Dec 23 00:45:56 EST 2015
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip