diff --git a/.idea/.name b/.idea/.name
index 382e0406e..634ba0111 100644
--- a/.idea/.name
+++ b/.idea/.name
@@ -1 +1 @@
-KeePassDroid
\ No newline at end of file
+keepassdroid
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index 3cff213df..000000000
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 3b312839b..000000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7e40dfca2..5d1998103 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -43,20 +43,4 @@
-
-
-
-
- 1.7
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index c3c5f5663..58620619b 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,8 +2,8 @@
-
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7f4..6564d52db 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/app.iml b/app/app.iml
index d7577ac80..1ff741123 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -1,5 +1,5 @@
-
+
@@ -87,7 +87,6 @@
-
@@ -109,5 +108,7 @@
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index b7c64b230..e6a6d9cea 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,7 +7,7 @@ model {
defaultConfig.with {
applicationId = "com.android.keepass"
- minSdkVersion.apiLevel = 3
+ minSdkVersion.apiLevel = 9
targetSdkVersion.apiLevel = 12
versionCode = 151
versionName = "2.0.6.1"
@@ -71,6 +71,8 @@ model {
dependencies {
androidTestCompile files('libs/junit4.jar')
+ compile 'com.journeyapps:zxing-android-embedded:3.0.0@aar'
+ compile 'com.google.zxing:core:3.2.0'
// Set this dependency if you want to use Hamcrest matching
//androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
}
diff --git a/app/src/main/java/com/keepassdroid/EntryActivity.java b/app/src/main/java/com/keepassdroid/EntryActivity.java
index c8ba6c318..3ef8f3629 100644
--- a/app/src/main/java/com/keepassdroid/EntryActivity.java
+++ b/app/src/main/java/com/keepassdroid/EntryActivity.java
@@ -28,6 +28,7 @@
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -38,6 +39,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
@@ -49,6 +51,7 @@
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@@ -56,6 +59,7 @@
import com.android.keepass.KeePass;
import com.android.keepass.R;
+import com.google.zxing.WriterException;
import com.keepassdroid.app.App;
import com.keepassdroid.compat.ActivityCompat;
import com.keepassdroid.database.PwDatabase;
@@ -64,6 +68,7 @@
import com.keepassdroid.database.exception.SamsungClipboardException;
import com.keepassdroid.intents.Intents;
import com.keepassdroid.utils.EmptyUtils;
+import com.keepassdroid.utils.QrCodeGenerator;
import com.keepassdroid.utils.Types;
import com.keepassdroid.utils.Util;
@@ -73,22 +78,24 @@ public class EntryActivity extends LockCloseHideActivity {
public static final int NOTIFY_USERNAME = 1;
public static final int NOTIFY_PASSWORD = 2;
-
+ public static final int NOTIFY_QRCODE = 3;
+
+
public static void Launch(Activity act, PwEntry pw, int pos) {
Intent i;
-
+
if ( pw instanceof PwEntryV4 ) {
i = new Intent(act, EntryActivityV4.class);
} else {
i = new Intent(act, EntryActivity.class);
}
-
+
i.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
i.putExtra(KEY_REFRESH_POS, pos);
-
+
act.startActivityForResult(i,0);
}
-
+
protected PwEntry mEntry;
private Timer mTimer = new Timer();
private boolean mShowPassword;
@@ -96,14 +103,14 @@ public static void Launch(Activity act, PwEntry pw, int pos) {
private NotificationManager mNM;
private BroadcastReceiver mIntentReceiver;
protected boolean readOnly = false;
-
+
private DateFormat dateFormat;
private DateFormat timeFormat;
-
+
protected void setEntryView() {
setContentView(R.layout.entry_view);
}
-
+
protected void setupEditButtons() {
Button edit = (Button) findViewById(R.id.entry_edit);
edit.setOnClickListener(new View.OnClickListener() {
@@ -111,12 +118,12 @@ protected void setupEditButtons() {
public void onClick(View v) {
EntryEditActivity.Launch(EntryActivity.this, mEntry);
}
-
+
});
-
+
if (readOnly) {
edit.setVisibility(View.GONE);
-
+
View divider = findViewById(R.id.entry_divider2);
divider.setVisibility(View.GONE);
}
@@ -126,10 +133,10 @@ public void onClick(View v) {
protected void onCreate(Bundle savedInstanceState) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mShowPassword = ! prefs.getBoolean(getString(R.string.maskpass_key), getResources().getBoolean(R.bool.maskpass_default));
-
+
super.onCreate(savedInstanceState);
setEntryView();
-
+
Context appCtx = getApplicationContext();
dateFormat = android.text.format.DateFormat.getDateFormat(appCtx);
timeFormat = android.text.format.DateFormat.getTimeFormat(appCtx);
@@ -148,41 +155,49 @@ protected void onCreate(Bundle savedInstanceState) {
UUID uuid = Types.bytestoUUID(i.getByteArrayExtra(KEY_ENTRY));
mPos = i.getIntExtra(KEY_REFRESH_POS, -1);
assert(uuid != null);
-
+
mEntry = db.pm.entries.get(uuid);
if (mEntry == null) {
Toast.makeText(this, R.string.entry_not_found, Toast.LENGTH_LONG).show();
finish();
return;
}
-
+
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
ActivityCompat.invalidateOptionsMenu(this);
-
+
// Update last access time.
mEntry.touch(false, false);
-
+
fillData(false);
setupEditButtons();
-
+
// Notification Manager
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
-
+
if ( mEntry.getPassword().length() > 0 ) {
// only show notification if password is available
Notification password = getNotification(Intents.COPY_PASSWORD, R.string.copy_password);
mNM.notify(NOTIFY_PASSWORD, password);
}
-
+
if ( mEntry.getUsername().length() > 0 ) {
// only show notification if username is available
Notification username = getNotification(Intents.COPY_USERNAME, R.string.copy_username);
mNM.notify(NOTIFY_USERNAME, username);
}
-
+
+ //Ajouter la notification pour le qr code
+ if ( mEntry.getPassword().length() > 0 ) {
+ // only show notification if password is available
+ Notification qrcode = getNotification(Intents.SHOW_QRCODE, R.string.notify_qrcode);
+ mNM.notify(NOTIFY_QRCODE, qrcode);
+ }
+
+
mIntentReceiver = new BroadcastReceiver() {
-
+
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -197,70 +212,88 @@ public void onReceive(Context context, Intent intent) {
if ( password.length() > 0 ) {
timeoutCopyToClipboard(new String(mEntry.getPassword()));
}
+ } else if (action.equals(Intents.SHOW_QRCODE)) {
+ String password = new String(mEntry.getPassword());
+ if ( password.length() > 0 ) {
+ //Open a dialog with qrcode
+ try {
+ Bitmap qrCode = QrCodeGenerator.genQrCodeBitmap(password);
+ Dialog dialogQrCode = new Dialog(context);
+ dialogQrCode.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+ dialogQrCode.setContentView(getLayoutInflater().inflate(R.layout.qrcode
+ , null));
+ dialogQrCode.show();
+ ImageView qrCodeView = (ImageView) dialogQrCode.findViewById(R.id.qrcode);
+ qrCodeView.setImageBitmap(qrCode);
+ } catch (WriterException e) {
+ e.printStackTrace();
+ }
+ }
}
}
};
-
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intents.COPY_USERNAME);
filter.addAction(Intents.COPY_PASSWORD);
+ filter.addAction(Intents.SHOW_QRCODE);
registerReceiver(mIntentReceiver, filter);
}
-
+
@Override
protected void onDestroy() {
// These members might never get initialized if the app timed out
if ( mIntentReceiver != null ) {
unregisterReceiver(mIntentReceiver);
}
-
+
if ( mNM != null ) {
try {
- mNM.cancelAll();
+ mNM.cancelAll();
} catch (SecurityException e) {
// Some android devices give a SecurityException when trying to cancel notifications without the WAKE_LOCK permission,
// we'll ignore these.
}
}
-
+
super.onDestroy();
}
private Notification getNotification(String intentText, int descResId) {
String desc = getString(descResId);
Notification notify = new Notification(R.drawable.notify, desc, System.currentTimeMillis());
-
+
Intent intent = new Intent(intentText);
PendingIntent pending = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-
+
notify.setLatestEventInfo(this, getString(R.string.app_name), desc, pending);
-
+
return notify;
}
-
+
private String getDateTime(Date dt) {
return dateFormat.format(dt) + " " + timeFormat.format(dt);
-
+
}
-
+
protected void fillData(boolean trimList) {
ImageView iv = (ImageView) findViewById(R.id.entry_icon);
Database db = App.getDB();
db.drawFactory.assignDrawableTo(iv, getResources(), mEntry.getIcon());
-
+
PwDatabase pm = db.pm;
populateText(R.id.entry_title, mEntry.getTitle(true, pm));
populateText(R.id.entry_user_name, mEntry.getUsername(true, pm));
-
+
populateText(R.id.entry_url, mEntry.getUrl(true, pm));
populateText(R.id.entry_password, mEntry.getPassword(true, pm));
setPasswordStyle();
-
+
populateText(R.id.entry_created, getDateTime(mEntry.getCreationTime()));
populateText(R.id.entry_modified, getDateTime(mEntry.getLastModificationTime()));
populateText(R.id.entry_accessed, getDateTime(mEntry.getLastAccessTime()));
-
+
Date expires = mEntry.getExpiryTime();
if ( mEntry.expires() ) {
populateText(R.id.entry_expires, getDateTime(expires));
@@ -270,7 +303,7 @@ protected void fillData(boolean trimList) {
populateText(R.id.entry_comment, mEntry.getNotes(true, pm));
}
-
+
private void populateText(int viewId, int resId) {
TextView tv = (TextView) findViewById(viewId);
tv.setText(resId);
@@ -297,21 +330,21 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
-
+
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.entry, menu);
-
+
MenuItem togglePassword = menu.findItem(R.id.menu_toggle_pass);
if ( mShowPassword ) {
togglePassword.setTitle(R.string.menu_hide_password);
} else {
togglePassword.setTitle(R.string.menu_showpass);
}
-
+
MenuItem gotoUrl = menu.findItem(R.id.menu_goto_url);
MenuItem copyUser = menu.findItem(R.id.menu_copy_user);
MenuItem copyPass = menu.findItem(R.id.menu_copy_pass);
-
+
// In API >= 11 onCreateOptionsMenu may be called before onCreate completes
// so mEntry may not be set
if (mEntry == null) {
@@ -334,10 +367,10 @@ public boolean onCreateOptionsMenu(Menu menu) {
copyPass.setVisible(false);
}
}
-
+
return true;
}
-
+
private void setPasswordStyle() {
TextView password = (TextView) findViewById(R.id.entry_password);
@@ -351,61 +384,61 @@ private void setPasswordStyle() {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch ( item.getItemId() ) {
- case R.id.menu_donate:
- try {
- Util.gotoUrl(this, R.string.donate_url);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(this, R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show();
- return false;
- }
-
- return true;
- case R.id.menu_toggle_pass:
- if ( mShowPassword ) {
- item.setTitle(R.string.menu_showpass);
- mShowPassword = false;
- } else {
- item.setTitle(R.string.menu_hide_password);
- mShowPassword = true;
- }
- setPasswordStyle();
-
- return true;
-
- case R.id.menu_goto_url:
- String url;
- url = mEntry.getUrl();
-
- // Default http:// if no protocol specified
- if ( ! url.contains("://") ) {
- url = "http://" + url;
- }
-
- try {
- Util.gotoUrl(this, url);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(this, R.string.no_url_handler, Toast.LENGTH_LONG).show();
- }
- return true;
-
- case R.id.menu_copy_user:
- timeoutCopyToClipboard(mEntry.getUsername(true, App.getDB().pm));
- return true;
-
- case R.id.menu_copy_pass:
- timeoutCopyToClipboard(new String(mEntry.getPassword(true, App.getDB().pm)));
- return true;
-
- case R.id.menu_lock:
- App.setShutdown();
- setResult(KeePass.EXIT_LOCK);
- finish();
- return true;
+ case R.id.menu_donate:
+ try {
+ Util.gotoUrl(this, R.string.donate_url);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this, R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show();
+ return false;
+ }
+
+ return true;
+ case R.id.menu_toggle_pass:
+ if ( mShowPassword ) {
+ item.setTitle(R.string.menu_showpass);
+ mShowPassword = false;
+ } else {
+ item.setTitle(R.string.menu_hide_password);
+ mShowPassword = true;
+ }
+ setPasswordStyle();
+
+ return true;
+
+ case R.id.menu_goto_url:
+ String url;
+ url = mEntry.getUrl();
+
+ // Default http:// if no protocol specified
+ if ( ! url.contains("://") ) {
+ url = "http://" + url;
+ }
+
+ try {
+ Util.gotoUrl(this, url);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this, R.string.no_url_handler, Toast.LENGTH_LONG).show();
+ }
+ return true;
+
+ case R.id.menu_copy_user:
+ timeoutCopyToClipboard(mEntry.getUsername(true, App.getDB().pm));
+ return true;
+
+ case R.id.menu_copy_pass:
+ timeoutCopyToClipboard(new String(mEntry.getPassword(true, App.getDB().pm)));
+ return true;
+
+ case R.id.menu_lock:
+ App.setShutdown();
+ setResult(KeePass.EXIT_LOCK);
+ finish();
+ return true;
}
-
+
return super.onOptionsItemSelected(item);
}
-
+
private void timeoutCopyToClipboard(String text) {
try {
Util.copyToClipboard(this, text);
@@ -413,36 +446,36 @@ private void timeoutCopyToClipboard(String text) {
showSamsungDialog();
return;
}
-
+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String sClipClear = prefs.getString(getString(R.string.clipboard_timeout_key), getString(R.string.clipboard_timeout_default));
-
+
long clipClearTime = Long.parseLong(sClipClear);
-
+
if ( clipClearTime > 0 ) {
mTimer.schedule(new ClearClipboardTask(this, text), clipClearTime);
}
}
-
+
// Setup to allow the toast to happen in the foreground
final Handler uiThreadCallback = new Handler();
// Task which clears the clipboard, and sends a toast to the foreground.
private class ClearClipboardTask extends TimerTask {
-
+
private final String mClearText;
private final Context mCtx;
-
+
ClearClipboardTask(Context ctx, String clearText) {
mClearText = clearText;
mCtx = ctx;
}
-
+
@Override
public void run() {
String currentClip = Util.getClipboard(mCtx);
-
+
if ( currentClip.equals(mClearText) ) {
try {
Util.copyToClipboard(mCtx, "");
@@ -453,7 +486,7 @@ public void run() {
}
}
}
-
+
private void showSamsungDialog() {
String text = getString(R.string.clipboard_error).concat(System.getProperty("line.separator")).concat(getString(R.string.clipboard_error_url));
SpannableString s = new SpannableString(text);
@@ -462,17 +495,17 @@ private void showSamsungDialog() {
tv.setAutoLinkMask(RESULT_OK);
tv.setMovementMethod(LinkMovementMethod.getInstance());
Linkify.addLinks(s, Linkify.WEB_URLS);
-
+
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.clipboard_error_title)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- })
- .setView(tv)
- .show();
-
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ })
+ .setView(tv)
+ .show();
+
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/keepassdroid/intents/Intents.java b/app/src/main/java/com/keepassdroid/intents/Intents.java
index a214c3a63..ed2f6f3be 100644
--- a/app/src/main/java/com/keepassdroid/intents/Intents.java
+++ b/app/src/main/java/com/keepassdroid/intents/Intents.java
@@ -20,9 +20,10 @@
public class Intents {
public static final String TIMEOUT = "com.keepassdroid.timeout";
-
+
public static final String COPY_USERNAME = "com.keepassdroid.copy_username";
public static final String COPY_PASSWORD = "com.keepassdroid.copy_password";
+ public static final String SHOW_QRCODE = "com.keepassdroid.show_qrcode";
public static final String OPEN_INTENTS_FILE_BROWSE = "org.openintents.action.PICK_FILE";
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/keepassdroid/utils/QrCodeGenerator.java b/app/src/main/java/com/keepassdroid/utils/QrCodeGenerator.java
new file mode 100644
index 000000000..1fe198747
--- /dev/null
+++ b/app/src/main/java/com/keepassdroid/utils/QrCodeGenerator.java
@@ -0,0 +1,38 @@
+package com.keepassdroid.utils;
+
+import android.graphics.Bitmap;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+
+public class QrCodeGenerator {
+
+ private static final int WIDTH = 800;
+ private static final int WHITE = 0xFFFFFFFF;
+ private static final int BLACK = 0xFF000000;
+
+ public static Bitmap genQrCodeBitmap(String str) throws WriterException {
+ BitMatrix result;
+ try {
+ result = new MultiFormatWriter().encode(str,
+ BarcodeFormat.QR_CODE, WIDTH, WIDTH, null);
+ } catch (IllegalArgumentException iae) {
+ // Unsupported format
+ return null;
+ }
+ int w = result.getWidth();
+ int h = result.getHeight();
+ int[] pixels = new int[w * h];
+ for (int y = 0; y < h; y++) {
+ int offset = y * w;
+ for (int x = 0; x < w; x++) {
+ pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
+ }
+ }
+ Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ bitmap.setPixels(pixels, 0, WIDTH, 0, 0, w, h);
+ return bitmap;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/qrcode.xml b/app/src/main/res/layout/qrcode.xml
new file mode 100644
index 000000000..53829399c
--- /dev/null
+++ b/app/src/main/res/layout/qrcode.xml
@@ -0,0 +1,6 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 800ecb19b..cf3012e60 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -50,6 +50,7 @@
Temps avant le vidage du presse-papier après copie du nom d\'utilisateur ou du mot de passe
Copier le nom d\'utilisateur dans le presse-papier
Copier le mot de passe dans le presse-papier
+ Générer le mot de passe sous forme de qr code
Création de la clé de base de données…
Groupe actuel\u00A0:
Groupe actuel\u00A0: Racine
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f1126abd6..ed5234868 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -50,6 +50,7 @@
Time before clearing clipboard after copying username or password
Select to copy username to clipboard
Select to copy password to clipboard
+ Select to generate a qrcode
Creating database key…
Current Group:
Current Group: Root
diff --git a/keepassdroid.iml b/keepassdroid.iml
new file mode 100644
index 000000000..6b5c6bb4a
--- /dev/null
+++ b/keepassdroid.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file