From 2f064abc4bc80793e4f2c3f8bf0e12132b160c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Friedger=20Mu=CC=88ffke?= Date: Wed, 14 Oct 2015 11:01:23 +0200 Subject: [PATCH] format ALL the files --- .../src/estreamj/ciphers/trivium/Trivium.java | 302 +-- Safe/src/estreamj/framework/ESJException.java | 30 +- Safe/src/estreamj/framework/Engine.java | 235 +- Safe/src/estreamj/framework/ICipher.java | 160 +- Safe/src/estreamj/framework/ICipherMaker.java | 31 +- Safe/src/estreamj/framework/Utils.java | 391 ++- .../openintents/intents/CryptoIntents.java | 312 ++- .../intents/FileManagerIntents.java | 73 +- .../src/org/openintents/safe/AskPassword.java | 1425 +++++----- Safe/src/org/openintents/safe/Backup.java | 300 +-- Safe/src/org/openintents/safe/CSVReader.java | 465 ++-- Safe/src/org/openintents/safe/CSVWriter.java | 745 +++--- .../org/openintents/safe/CategoryEdit.java | 338 +-- .../org/openintents/safe/CategoryEntry.java | 64 +- .../org/openintents/safe/CategoryList.java | 2349 +++++++++-------- .../safe/CategoryListItemAdapter.java | 167 +- Safe/src/org/openintents/safe/ChangePass.java | 704 ++--- .../safe/CryptoContentProvider.java | 344 +-- .../org/openintents/safe/CryptoHelper.java | 1965 +++++++------- .../safe/CryptoHelperException.java | 10 +- Safe/src/org/openintents/safe/DBHelper.java | 1668 ++++++------ Safe/src/org/openintents/safe/FrontDoor.java | 6 +- Safe/src/org/openintents/safe/Help.java | 260 +- .../org/openintents/safe/InputStreamData.java | 3 - .../org/openintents/safe/IntentHandler.java | 861 +++--- Safe/src/org/openintents/safe/Intents.java | 3 - .../org/openintents/safe/LogOffActivity.java | 148 +- .../openintents/safe/OutputStreamData.java | 1 - .../openintents/safe/PackageAccessEntry.java | 8 +- Safe/src/org/openintents/safe/PassEdit.java | 267 +- .../openintents/safe/PassEditFragment.java | 800 +++--- Safe/src/org/openintents/safe/PassEntry.java | 49 +- Safe/src/org/openintents/safe/PassGen.java | 469 ++-- Safe/src/org/openintents/safe/PassList.java | 1061 ++++---- Safe/src/org/openintents/safe/PassView.java | 1445 +++++----- Safe/src/org/openintents/safe/Passwords.java | 1056 ++++---- .../src/org/openintents/safe/Preferences.java | 505 ++-- Safe/src/org/openintents/safe/Restore.java | 675 ++--- .../org/openintents/safe/RestoreDataSet.java | 328 ++- .../openintents/safe/RestoreFirstTime.java | 102 +- .../org/openintents/safe/RestoreHandler.java | 375 +-- Safe/src/org/openintents/safe/Safe.java | 65 +- Safe/src/org/openintents/safe/Search.java | 53 +- .../src/org/openintents/safe/SearchEntry.java | 106 +- .../org/openintents/safe/SearchFragment.java | 705 ++--- .../safe/SearchListItemAdapter.java | 90 +- .../openintents/safe/SimpleGestureFilter.java | 356 +-- .../dialog/AllowExternalAccessDialog.java | 94 +- .../safe/dialog/DialogHostingActivity.java | 388 +-- .../safe/dialog/FilenameDialog.java | 127 +- .../safe/dialog/FirstTimeWarningDialog.java | 39 +- .../org/openintents/safe/password/Master.java | 56 +- .../safe/service/AutoLockService.java | 363 +-- .../safe/service/ServiceNotification.java | 157 +- .../safe/wrappers/CheckWrappers.java | 34 +- .../wrappers/honeycomb/ClipboardManager.java | 277 +- .../wrappers/honeycomb/WrapActionBar.java | 76 +- .../WrapNotificationBuilder.java | 79 +- .../org/openintents/util/SecureDelete.java | 120 +- .../openintents/intents/CryptoIntents.java | 204 +- .../samples/testsafe/TestSafe.java | 431 +-- .../org/openintents/safe/test/SafeTest.java | 499 ++-- 62 files changed, 12851 insertions(+), 11968 deletions(-) diff --git a/Safe/src/estreamj/ciphers/trivium/Trivium.java b/Safe/src/estreamj/ciphers/trivium/Trivium.java index 6f007d23..3a84d25c 100644 --- a/Safe/src/estreamj/ciphers/trivium/Trivium.java +++ b/Safe/src/estreamj/ciphers/trivium/Trivium.java @@ -1,4 +1,3 @@ - package estreamj.ciphers.trivium; import estreamj.framework.ESJException; @@ -7,45 +6,39 @@ import estreamj.framework.ICipherMaker; import estreamj.framework.Utils; -public class Trivium implements ICipher -{ - final static int KEY_SIZE_BITS = 80; - final static int IV_SIZE_BITS = 80; - - /////////////////////////////////////////////////////////////////////////// - - byte[] key = new byte[10]; - int[] s = new int[10]; - - /////////////////////////////////////////////////////////////////////////// - - public int getKeySize() - { - return KEY_SIZE_BITS >> 3; - } - - public int getNonceSize() - { - return IV_SIZE_BITS >> 3; - } - - public int getWordSize() - { - return 4; - } - - public boolean isPatented() - { - return false; - } - - public void process( - byte[] inbuf, - int inOfs, - byte[] outbuf, - int outOfs, - int len) throws ESJException - { +public class Trivium implements ICipher { + final static int KEY_SIZE_BITS = 80; + final static int IV_SIZE_BITS = 80; + + /////////////////////////////////////////////////////////////////////////// + + byte[] key = new byte[10]; + int[] s = new int[10]; + + /////////////////////////////////////////////////////////////////////////// + + public int getKeySize() { + return KEY_SIZE_BITS >> 3; + } + + public int getNonceSize() { + return IV_SIZE_BITS >> 3; + } + + public int getWordSize() { + return 4; + } + + public boolean isPatented() { + return false; + } + + public void process( + byte[] inbuf, + int inOfs, + byte[] outbuf, + int outOfs, + int len) throws ESJException { int s11 = s[0]; int s12 = s[1]; int s13 = s[2]; @@ -56,60 +49,72 @@ public void process( int s32 = s[7]; int s33 = s[8]; int s34 = s[9]; - - int outEnd = outOfs + (len & ~3); - - for (; outOfs < outEnd; outOfs+=4, inOfs+=4) - { - int t1, t2, t3, reg; - - t1 = ((s13 << 96-66) | (s12 >>> 66-64)) ^ ((s13 << 96-93 ) | (s12 >>> 93-64)); - t2 = ((s23 << 96-69) | (s22 >>> 69-64)) ^ ((s23 << 96-84 ) | (s22 >>> 84-64)); - t3 = ((s33 << 96-66) | (s32 >>> 66-64)) ^ ((s34 << 128-111) | (s33 >>> 111-96)); - + + int outEnd = outOfs + (len & ~3); + + for (; outOfs < outEnd; outOfs += 4, inOfs += 4) { + int t1, t2, t3, reg; + + t1 = ((s13 << 96 - 66) | (s12 >>> 66 - 64)) ^ ((s13 << 96 - 93) | (s12 >>> 93 - 64)); + t2 = ((s23 << 96 - 69) | (s22 >>> 69 - 64)) ^ ((s23 << 96 - 84) | (s22 >>> 84 - 64)); + t3 = ((s33 << 96 - 66) | (s32 >>> 66 - 64)) ^ ((s34 << 128 - 111) | (s33 >>> 111 - 96)); + reg = t1 ^ t2 ^ t3; - outbuf[outOfs ] = (byte)(inbuf[inOfs ] ^ reg); - outbuf[outOfs + 1] = (byte)(inbuf[inOfs + 1] ^ reg >> 8); - outbuf[outOfs + 2] = (byte)(inbuf[inOfs + 2] ^ reg >> 16); - outbuf[outOfs + 3] = (byte)(inbuf[inOfs + 3] ^ reg >> 24); - - t1 ^= (((s13 << 96-91 ) | (s12 >>> 91-64)) & ((s13 << 96-92 ) | (s12 >>> 92-64))) ^ ((s23 << 96-78) | (s22 >>> 78-64)); - t2 ^= (((s23 << 96-82 ) | (s22 >>> 82-64)) & ((s23 << 96-83 ) | (s22 >>> 83-64))) ^ ((s33 << 96-87) | (s32 >>> 87-64)); - t3 ^= (((s34 << 128-109) | (s33 >>> 109-96)) & ((s34 << 128-110) | (s33 >>> 110-96))) ^ ((s13 << 96-69) | (s12 >>> 69-64)); - - s13 = s12; s12 = s11; s11 = t3; - s23 = s22; s22 = s21; s21 = t1; - s34 = s33; s33 = s32; s32 = s31; s31 = t2; + outbuf[outOfs] = (byte) (inbuf[inOfs] ^ reg); + outbuf[outOfs + 1] = (byte) (inbuf[inOfs + 1] ^ reg >> 8); + outbuf[outOfs + 2] = (byte) (inbuf[inOfs + 2] ^ reg >> 16); + outbuf[outOfs + 3] = (byte) (inbuf[inOfs + 3] ^ reg >> 24); + + t1 ^= (((s13 << 96 - 91) | (s12 >>> 91 - 64)) & ((s13 << 96 - 92) | (s12 >>> 92 - 64))) ^ ((s23 << 96 - 78) | (s22 >>> 78 - 64)); + t2 ^= (((s23 << 96 - 82) | (s22 >>> 82 - 64)) & ((s23 << 96 - 83) | (s22 >>> 83 - 64))) ^ ((s33 << 96 - 87) | (s32 >>> 87 - 64)); + t3 ^= (((s34 << 128 - 109) | (s33 >>> 109 - 96)) & ((s34 << 128 - 110) | (s33 >>> 110 - 96))) ^ ((s13 << 96 - 69) | (s12 >>> 69 - 64)); + + s13 = s12; + s12 = s11; + s11 = t3; + s23 = s22; + s22 = s21; + s21 = t1; + s34 = s33; + s33 = s32; + s32 = s31; + s31 = t2; } - + // NOTE: could save some code memory by merging the two blocks, but that // would decrease the speed because of additional conditional jumps... outEnd = outOfs + (len & 3); //if (0 < outEnd) if (outOfs < outEnd) // Peli: Apr 3, 2009: BUGFIX { - int t1, t2, t3, reg; - - t1 = ((s13 << 96-66) | (s12 >>> 66-64)) ^ ((s13 << 96-93 ) | (s12 >>> 93-64)); - t2 = ((s23 << 96-69) | (s22 >>> 69-64)) ^ ((s23 << 96-84 ) | (s22 >>> 84-64)); - t3 = ((s33 << 96-66) | (s32 >>> 66-64)) ^ ((s34 << 128-111) | (s33 >>> 111-96)); - + int t1, t2, t3, reg; + + t1 = ((s13 << 96 - 66) | (s12 >>> 66 - 64)) ^ ((s13 << 96 - 93) | (s12 >>> 93 - 64)); + t2 = ((s23 << 96 - 69) | (s22 >>> 69 - 64)) ^ ((s23 << 96 - 84) | (s22 >>> 84 - 64)); + t3 = ((s33 << 96 - 66) | (s32 >>> 66 - 64)) ^ ((s34 << 128 - 111) | (s33 >>> 111 - 96)); + reg = t1 ^ t2 ^ t3; - for (;outOfs < outEnd; outOfs++, inOfs++) - { - outbuf[outOfs] = (byte)(inbuf[inOfs] ^ reg); - reg >>= 8; + for (; outOfs < outEnd; outOfs++, inOfs++) { + outbuf[outOfs] = (byte) (inbuf[inOfs] ^ reg); + reg >>= 8; } - t1 ^= (((s13 << 96-91 ) | (s12 >>> 91-64)) & ((s13 << 96-92 ) | (s12 >>> 92-64))) ^ ((s23 << 96-78) | (s22 >>> 78-64)); - t2 ^= (((s23 << 96-82 ) | (s22 >>> 82-64)) & ((s23 << 96-83 ) | (s22 >>> 83-64))) ^ ((s33 << 96-87) | (s32 >>> 87-64)); - t3 ^= (((s34 << 128-109) | (s33 >>> 109-96)) & ((s34 << 128-110) | (s33 >>> 110-96))) ^ ((s13 << 96-69) | (s12 >>> 69-64)); - - s13 = s12; s12 = s11; s11 = t3; - s23 = s22; s22 = s21; s21 = t1; - s34 = s33; s33 = s32; s32 = s31; s31 = t2; + t1 ^= (((s13 << 96 - 91) | (s12 >>> 91 - 64)) & ((s13 << 96 - 92) | (s12 >>> 92 - 64))) ^ ((s23 << 96 - 78) | (s22 >>> 78 - 64)); + t2 ^= (((s23 << 96 - 82) | (s22 >>> 82 - 64)) & ((s23 << 96 - 83) | (s22 >>> 83 - 64))) ^ ((s33 << 96 - 87) | (s32 >>> 87 - 64)); + t3 ^= (((s34 << 128 - 109) | (s33 >>> 109 - 96)) & ((s34 << 128 - 110) | (s33 >>> 110 - 96))) ^ ((s13 << 96 - 69) | (s12 >>> 69 - 64)); + + s13 = s12; + s12 = s11; + s11 = t3; + s23 = s22; + s22 = s21; + s21 = t1; + s34 = s33; + s33 = s32; + s32 = s31; + s31 = t2; } - + s[0] = s11; s[1] = s12; s[2] = s13; @@ -120,43 +125,39 @@ public void process( s[7] = s32; s[8] = s33; s[9] = s34; - } - - public void reset() throws ESJException - { - // key is cached already, nothing to do here - } - - public void setupKey( - int mode, - byte[] key, - int ofs) throws ESJException - { - System.arraycopy(key, ofs, this.key, 0, this.key.length); - } - - public void setupNonce( - byte[] nonce, - int ofs) throws ESJException - { - byte[] key = this.key; - int[] s = this.s; - - int s11 = Utils.readInt32LE(key, 0); - int s12 = Utils.readInt32LE(key, 4); - int s13 = ( key[8] & 0x0ff) | - ((key[9] << 8) & 0x0ff00); - int s21 = Utils.readInt32LE(nonce, ofs); - int s22 = Utils.readInt32LE(nonce, ofs + 4); - int s23 = ( nonce[ofs + 8] & 0x0ff) | - ((nonce[ofs + 9] << 8) & 0x0ff00); - int s31 = 0; - int s32 = 0; - int s33 = 0; - int s34 = 0x07000; - - - ///////////////!!!!!!!!!!!!!!!!!!!!!!!! + } + + public void reset() throws ESJException { + // key is cached already, nothing to do here + } + + public void setupKey( + int mode, + byte[] key, + int ofs) throws ESJException { + System.arraycopy(key, ofs, this.key, 0, this.key.length); + } + + public void setupNonce( + byte[] nonce, + int ofs) throws ESJException { + byte[] key = this.key; + int[] s = this.s; + + int s11 = Utils.readInt32LE(key, 0); + int s12 = Utils.readInt32LE(key, 4); + int s13 = (key[8] & 0x0ff) | + ((key[9] << 8) & 0x0ff00); + int s21 = Utils.readInt32LE(nonce, ofs); + int s22 = Utils.readInt32LE(nonce, ofs + 4); + int s23 = (nonce[ofs + 8] & 0x0ff) | + ((nonce[ofs + 9] << 8) & 0x0ff00); + int s31 = 0; + int s32 = 0; + int s33 = 0; + int s34 = 0x07000; + + ///////////////!!!!!!!!!!!!!!!!!!!!!!!! // System.out.printf( // "s11=%08x\n" + // "s12=%08x\n" + @@ -171,25 +172,30 @@ public void setupNonce( // s11, s12, s13, // s21, s22, s23, // s31, s32, s33, s34); - - - for (int i = 0; i < 4*9; i++) - { - int t1, t2, t3; - - t1 = ((s13 << 96-66) | (s12 >>> 66-64)) ^ ((s13 << 96-93 ) | (s12 >>> 93-64)); - t2 = ((s23 << 96-69) | (s22 >>> 69-64)) ^ ((s23 << 96-84 ) | (s22 >>> 84-64)); - t3 = ((s33 << 96-66) | (s32 >>> 66-64)) ^ ((s34 << 128-111) | (s33 >>> 111-96)); - - t1 ^= (((s13 << 96-91 ) | (s12 >>> 91-64)) & ((s13 << 96-92 ) | (s12 >>> 92-64))) ^ ((s23 << 96-78) | (s22 >>> 78-64)); - t2 ^= (((s23 << 96-82 ) | (s22 >>> 82-64)) & ((s23 << 96-83 ) | (s22 >>> 83-64))) ^ ((s33 << 96-87) | (s32 >>> 87-64)); - t3 ^= (((s34 << 128-109) | (s33 >>> 109-96)) & ((s34 << 128-110) | (s33 >>> 110-96))) ^ ((s13 << 96-69) | (s12 >>> 69-64)); - - s13 = s12; s12 = s11; s11 = t3; - s23 = s22; s22 = s21; s21 = t1; - s34 = s33; s33 = s32; s32 = s31; s31 = t2; + + for (int i = 0; i < 4 * 9; i++) { + int t1, t2, t3; + + t1 = ((s13 << 96 - 66) | (s12 >>> 66 - 64)) ^ ((s13 << 96 - 93) | (s12 >>> 93 - 64)); + t2 = ((s23 << 96 - 69) | (s22 >>> 69 - 64)) ^ ((s23 << 96 - 84) | (s22 >>> 84 - 64)); + t3 = ((s33 << 96 - 66) | (s32 >>> 66 - 64)) ^ ((s34 << 128 - 111) | (s33 >>> 111 - 96)); + + t1 ^= (((s13 << 96 - 91) | (s12 >>> 91 - 64)) & ((s13 << 96 - 92) | (s12 >>> 92 - 64))) ^ ((s23 << 96 - 78) | (s22 >>> 78 - 64)); + t2 ^= (((s23 << 96 - 82) | (s22 >>> 82 - 64)) & ((s23 << 96 - 83) | (s22 >>> 83 - 64))) ^ ((s33 << 96 - 87) | (s32 >>> 87 - 64)); + t3 ^= (((s34 << 128 - 109) | (s33 >>> 109 - 96)) & ((s34 << 128 - 110) | (s33 >>> 110 - 96))) ^ ((s13 << 96 - 69) | (s12 >>> 69 - 64)); + + s13 = s12; + s12 = s11; + s11 = t3; + s23 = s22; + s22 = s21; + s21 = t1; + s34 = s33; + s33 = s32; + s32 = s31; + s31 = t2; } - + s[0] = s11; s[1] = s12; s[2] = s13; @@ -200,25 +206,21 @@ public void setupNonce( s[7] = s32; s[8] = s33; s[9] = s34; - } - + } + /////////////////////////////////////////////////////////////////////////// - - static class Maker implements ICipherMaker - { - public ICipher create() throws ESJException - { + + static class Maker implements ICipherMaker { + public ICipher create() throws ESJException { return new Trivium(); } - public String getName() - { + public String getName() { return "Trivium"; } } - - public static void register() - { + + public static void register() { Engine.registerCipher(new Maker()); } -} \ No newline at end of file +} diff --git a/Safe/src/estreamj/framework/ESJException.java b/Safe/src/estreamj/framework/ESJException.java index 45b3d7bf..eaf09c94 100644 --- a/Safe/src/estreamj/framework/ESJException.java +++ b/Safe/src/estreamj/framework/ESJException.java @@ -1,23 +1,21 @@ - package estreamj.framework; -public class ESJException extends Exception -{ - private static final long serialVersionUID = 6375271013846829471L; +public class ESJException extends Exception { + private static final long serialVersionUID = 6375271013846829471L; - public ESJException() { - super(); - } + public ESJException() { + super(); + } - public ESJException(String message) { - super(message); - } + public ESJException(String message) { + super(message); + } - public ESJException(Throwable cause) { - super(cause); - } + public ESJException(Throwable cause) { + super(cause); + } - public ESJException(String message, Throwable cause) { - super(message, cause); - } + public ESJException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/Safe/src/estreamj/framework/Engine.java b/Safe/src/estreamj/framework/Engine.java index 678dd5e2..1995053a 100644 --- a/Safe/src/estreamj/framework/Engine.java +++ b/Safe/src/estreamj/framework/Engine.java @@ -1,132 +1,127 @@ - package estreamj.framework; -import java.util.*; -import java.lang.reflect.*; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.HashMap; +import java.util.Vector; /** * The engine accumulates all the stream ciphers available. All implementations * register with the engine by themselves. */ -public class Engine -{ - /** - * @return the names of all ciphers registered; can be empty if no ciphers - * have been registered so far - */ - public static String[] getCipherNames() - { - String[] result; - - synchronized(_cphMks) - { - Vector lst = new Vector(); - lst.addAll(_cphMks.keySet()); - Collections.sort(lst); - result = lst.toArray(new String[lst.size()]); - } - - return result; - } - - /** - * Creates a new cipher instance. - * @param name name of the cipher to make - * @return new cipher instance - * @throws ESJException if any error occured - */ - public static ICipher createCipher(String name) throws ESJException - { - ICipherMaker maker; - - synchronized(_cphMks) - { - maker = _cphMks.get(name); - if (null == maker) - { - throw new ESJException("no maker registered for cipher \"" + - name + "\""); - } - } - return maker.create(); - } - - /////////////////////////////////////////////////////////////////////////// +public class Engine { + /** + * @return the names of all ciphers registered; can be empty if no ciphers + * have been registered so far + */ + public static String[] getCipherNames() { + String[] result; + + synchronized (_cphMks) { + Vector lst = new Vector(); + lst.addAll(_cphMks.keySet()); + Collections.sort(lst); + result = lst.toArray(new String[lst.size()]); + } + + return result; + } + + /** + * Creates a new cipher instance. + * + * @param name name of the cipher to make + * @return new cipher instance + * @throws ESJException if any error occured + */ + public static ICipher createCipher(String name) throws ESJException { + ICipherMaker maker; + + synchronized (_cphMks) { + maker = _cphMks.get(name); + if (null == maker) { + throw new ESJException( + "no maker registered for cipher \"" + + name + "\"" + ); + } + } + return maker.create(); + } + + /////////////////////////////////////////////////////////////////////////// + + static HashMap _cphMks = + new HashMap(); + + /** + * Called by cipher implementations to register their factories, usually + * during startup time. + * + * @param cphMk the factory to register + */ + public static void registerCipher(ICipherMaker cphMk) { + String name = cphMk.getName(); + + synchronized (_cphMks) { + if (_cphMks.containsKey(name)) { + System.err.println( + "cipher \"" + name + + "\" has been registered already" + ); + System.exit(1); + } + _cphMks.put(cphMk.getName(), cphMk); + } + } - static HashMap _cphMks = - new HashMap(); + /////////////////////////////////////////////////////////////////////////// - /** - * Called by cipher implementations to register their factories, usually - * during startup time. - * @param cphMk the factory to register - */ - public static void registerCipher(ICipherMaker cphMk) - { - String name = cphMk.getName(); - - synchronized(_cphMks) - { - if (_cphMks.containsKey(name)) - { - System.err.println("cipher \"" + name + - "\" has been registered already"); - System.exit(1); - } - _cphMks.put(cphMk.getName(), cphMk); - } - } + // all the cipher classes must be listed here, the rest of the registration + // is done via reflection; this is done by having every class implementing + // a 'public static void register()' method (see below) + @SuppressWarnings("rawtypes") + static Class[] _cipherClasses = + { + //estreamj.ciphers.phelix.Phelix.class, + //estreamj.ciphers.hc256.HC256.class, + //estreamj.ciphers.salsa20.Salsa20.class, + //estreamj.ciphers.aes.AESCTR.class, + //estreamj.ciphers.mickey.MICKEY.class, + //estreamj.ciphers.mickey.MICKEY128.class, + //estreamj.ciphers.hermes8.Hermes8.class, + //estreamj.ciphers.rc4.RC4.class, + //estreamj.ciphers.dragon.Dragon.class, + //estreamj.ciphers.lex.LEX.class, + estreamj.ciphers.trivium.Trivium.class//, + //estreamj.ciphers.sosemanuk.Sosemanuk.class, + //estreamj.ciphers.grain.GrainP2.class, + //estreamj.ciphers.grain.Grain128.class, + //estreamj.ciphers.nil.Nil.class + }; - /////////////////////////////////////////////////////////////////////////// - - // all the cipher classes must be listed here, the rest of the registration - // is done via reflection; this is done by having every class implementing - // a 'public static void register()' method (see below) - @SuppressWarnings("rawtypes") - static Class[] _cipherClasses = - { - //estreamj.ciphers.phelix.Phelix.class, - //estreamj.ciphers.hc256.HC256.class, - //estreamj.ciphers.salsa20.Salsa20.class, - //estreamj.ciphers.aes.AESCTR.class, - //estreamj.ciphers.mickey.MICKEY.class, - //estreamj.ciphers.mickey.MICKEY128.class, - //estreamj.ciphers.hermes8.Hermes8.class, - //estreamj.ciphers.rc4.RC4.class, - //estreamj.ciphers.dragon.Dragon.class, - //estreamj.ciphers.lex.LEX.class, - estreamj.ciphers.trivium.Trivium.class//, - //estreamj.ciphers.sosemanuk.Sosemanuk.class, - //estreamj.ciphers.grain.GrainP2.class, - //estreamj.ciphers.grain.Grain128.class, - //estreamj.ciphers.nil.Nil.class - }; + /////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - - static - { - try - { - for (int i = 0; i < _cipherClasses.length; i++) - { - // check if the register method is there and static - Class cls = _cipherClasses[i]; - Method mthd = cls.getMethod("register", (Class[])null); - if (Modifier.STATIC != (mthd.getModifiers() & Modifier.STATIC)) - { - throw new Exception( - "register() method is not static (" + cls + ")"); - } - // ready to register - mthd.invoke(null, (Object[])null); - } - } - catch (Exception e) - { - System.err.println( - "cipher registration error (" + e.getMessage() + ")"); - System.exit(1); - } - } + static { + try { + for (int i = 0; i < _cipherClasses.length; i++) { + // check if the register method is there and static + Class cls = _cipherClasses[i]; + Method mthd = cls.getMethod("register", (Class[]) null); + if (Modifier.STATIC != (mthd.getModifiers() & Modifier.STATIC)) { + throw new Exception( + "register() method is not static (" + cls + ")" + ); + } + // ready to register + mthd.invoke(null, (Object[]) null); + } + } catch (Exception e) { + System.err.println( + "cipher registration error (" + e.getMessage() + ")" + ); + System.exit(1); + } + } } diff --git a/Safe/src/estreamj/framework/ICipher.java b/Safe/src/estreamj/framework/ICipher.java index 10a6cfe9..93c84b34 100644 --- a/Safe/src/estreamj/framework/ICipher.java +++ b/Safe/src/estreamj/framework/ICipher.java @@ -1,4 +1,3 @@ - package estreamj.framework; /** @@ -7,85 +6,88 @@ * sizes, MAC computation or not, etc.) it should then implement a version for * each of them - this keeps the actual testing logic simple. Simple is good. */ -public interface ICipher -{ - /** - * mode: instance is used for encryption - */ - public final static int MODE_ENCRYPT = 0; +public interface ICipher { + /** + * mode: instance is used for encryption + */ + public final static int MODE_ENCRYPT = 0; + + /** + * mode: instance is used for decryption + */ + public final static int MODE_DECRYPT = 1; + + /////////////////////////////////////////////////////////////////////////// + + /** + * @return true: algorithm is patented, check with vendor for license + * details / false: free to use in private and commerical applications + */ + public boolean isPatented(); + + /** + * @return key size in bytes + */ + public int getKeySize(); + + /** + * @return nonce size in bytes. + */ + public int getNonceSize(); + + /** + * @return alignment of data needed during calls into process() + */ + public int getWordSize(); + + /////////////////////////////////////////////////////////////////////////// + + /** + * Resets the instance, so it can be reused. + * + * @throws ESJException if any error occurs + */ + public void reset() throws ESJException; + + /** + * Sets up a new key with the existing instance. + * + * @param mode see MODE_xxx + * @param key buffer with key material + * @param ofs where the key starts + * @throws ESJException if any error occurs + */ + public void setupKey(int mode, byte[] key, int ofs) + throws ESJException; - /** - * mode: instance is used for decryption - */ - public final static int MODE_DECRYPT = 1; - - /////////////////////////////////////////////////////////////////////////// - - /** - * @return true: algorithm is patented, check with vendor for license - * details / false: free to use in private and commerical applications - */ - public boolean isPatented(); - - /** - * @return key size in bytes - */ - public int getKeySize(); - - /** - * @return nonce size in bytes. - */ - public int getNonceSize(); - - /** - * @return alignment of data needed during calls into process() - */ - public int getWordSize(); + /** + * Sets up a new nonce with the existing cipher instance. + * + * @param mode see MODE_xxx + * @param nonce buffer with nonce material + * @param ofs where the nonce starts + * @throws ESJException if any error occurs + */ + public void setupNonce(byte[] nonce, int ofs) + throws ESJException; - /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// - /** - * Resets the instance, so it can be reused. - * @exception ESJException if any error occurs - */ - public void reset() throws ESJException; - - /** - * Sets up a new key with the existing instance. - * @param mode see MODE_xxx - * @param key buffer with key material - * @param ofs where the key starts - * @exception ESJException if any error occurs - */ - public void setupKey(int mode, byte[] key, int ofs) - throws ESJException; - - /** - * Sets up a new nonce with the existing cipher instance. - * @param mode see MODE_xxx - * @param nonce buffer with nonce material - * @param ofs where the nonce starts - * @exception ESJException if any error occurs - */ - public void setupNonce(byte[] nonce, int ofs) - throws ESJException; - - /////////////////////////////////////////////////////////////////////////// - - /** - * Processes data. - * @param inbuf input buffer - * @param inOfs where to start reading from the input buffer - * @param outbuf output buffer - * @param outOfs where to start writing in the output buffer - * @param len number of bytes to process, must be aligned to the cipher's - * word size except on the last call where an arbitrary size can be used - * @throws ESJException in any error occured - */ - public void process( - byte[] inbuf, - int inOfs, - byte[] outbuf, - int outOfs, - int len) throws ESJException; + /** + * Processes data. + * + * @param inbuf input buffer + * @param inOfs where to start reading from the input buffer + * @param outbuf output buffer + * @param outOfs where to start writing in the output buffer + * @param len number of bytes to process, must be aligned to the cipher's + * word size except on the last call where an arbitrary size can be used + * @throws ESJException in any error occured + */ + public void process( + byte[] inbuf, + int inOfs, + byte[] outbuf, + int outOfs, + int len) throws ESJException; } diff --git a/Safe/src/estreamj/framework/ICipherMaker.java b/Safe/src/estreamj/framework/ICipherMaker.java index ffaa8671..039b5b73 100644 --- a/Safe/src/estreamj/framework/ICipherMaker.java +++ b/Safe/src/estreamj/framework/ICipherMaker.java @@ -1,22 +1,21 @@ - package estreamj.framework; /** * Simple cipher factory. */ -public interface ICipherMaker -{ - /** - * @return the name of cipher, which is used for queries - so it must be - * unique - */ - public String getName(); - - /** - * Create a new cipher instance. - * @return new instance, which can also be of the type ICipherMAC, use the - * "instanceof" keyword to find out what you are dealing with - * @throws ESJException if any error occured - */ - public ICipher create() throws ESJException; +public interface ICipherMaker { + /** + * @return the name of cipher, which is used for queries - so it must be + * unique + */ + public String getName(); + + /** + * Create a new cipher instance. + * + * @return new instance, which can also be of the type ICipherMAC, use the + * "instanceof" keyword to find out what you are dealing with + * @throws ESJException if any error occured + */ + public ICipher create() throws ESJException; } diff --git a/Safe/src/estreamj/framework/Utils.java b/Safe/src/estreamj/framework/Utils.java index 97f9336d..35cf1285 100644 --- a/Safe/src/estreamj/framework/Utils.java +++ b/Safe/src/estreamj/framework/Utils.java @@ -1,230 +1,193 @@ - package estreamj.framework; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; import java.util.Arrays; -public class Utils -{ - public static void fillPattern123(byte[] buf, int ofs, int len) - { - int counter, end; - - counter = 0; - end = ofs + len; - while (ofs < end) - { - buf[ofs++] = (byte)counter++; - } - } - - public static boolean checkPattern123(byte[] buf, int ofs, int len) - { - int counter, end; - - counter = 0; - end = ofs + len; - while (ofs < end) - { - if (buf[ofs] != (byte)counter) - { - return false; - } - counter++; - ofs++; - } - return true; - } - - public static byte[] makeOutputBuffer(int len, int extraLen) - { +public class Utils { + public static void fillPattern123(byte[] buf, int ofs, int len) { + int counter, end; + + counter = 0; + end = ofs + len; + while (ofs < end) { + buf[ofs++] = (byte) counter++; + } + } + + public static boolean checkPattern123(byte[] buf, int ofs, int len) { + int counter, end; + + counter = 0; + end = ofs + len; + while (ofs < end) { + if (buf[ofs] != (byte) counter) { + return false; + } + counter++; + ofs++; + } + return true; + } + + public static byte[] makeOutputBuffer(int len, int extraLen) { byte[] result = new byte[len + extraLen]; - Arrays.fill(result, (byte)0xcc); + Arrays.fill(result, (byte) 0xcc); return result; } - + public static boolean arraysEquals( - byte[] a, int ofsA, byte[] b, int ofsB, int len) - { - int end = ofsA + len; - while (ofsA < end) - { - if (b[ofsB++] != a[ofsA++]) - { - return false; - } - } - return true; - } - - public final static int readInt32LE(byte[] data, int ofs) - { - return ( data[ofs + 3] << 24) | - ((data[ofs + 2] & 0xff) << 16) | - ((data[ofs + 1] & 0xff) << 8) | - (data[ofs ] & 0xff); + byte[] a, int ofsA, byte[] b, int ofsB, int len) { + int end = ofsA + len; + while (ofsA < end) { + if (b[ofsB++] != a[ofsA++]) { + return false; + } + } + return true; + } + + public final static int readInt32LE(byte[] data, int ofs) { + return (data[ofs + 3] << 24) | + ((data[ofs + 2] & 0xff) << 16) | + ((data[ofs + 1] & 0xff) << 8) | + (data[ofs] & 0xff); } - - public final static void writeInt32LE(int value, byte[] data, int ofs) - { - data[ofs ] = (byte)(value ); - data[ofs + 1] = (byte)(value >>> 8); - data[ofs + 2] = (byte)(value >>> 16); - data[ofs + 3] = (byte)(value >>> 24); + + public final static void writeInt32LE(int value, byte[] data, int ofs) { + data[ofs] = (byte) (value); + data[ofs + 1] = (byte) (value >>> 8); + data[ofs + 2] = (byte) (value >>> 16); + data[ofs + 3] = (byte) (value >>> 24); } - public final static int readInt32BE(byte[] data, int ofs) - { - return ( data[ofs ] << 24) | - ((data[ofs + 1] & 0xff) << 16) | - ((data[ofs + 2] & 0xff) << 8) | - (data[ofs + 3] & 0xff); + public final static int readInt32BE(byte[] data, int ofs) { + return (data[ofs] << 24) | + ((data[ofs + 1] & 0xff) << 16) | + ((data[ofs + 2] & 0xff) << 8) | + (data[ofs + 3] & 0xff); } - - public final static void writeInt32BE(int value, byte[] data, int ofs) - { - data[ofs + 3] = (byte)(value ); - data[ofs + 2] = (byte)(value >>> 8); - data[ofs + 1] = (byte)(value >>> 16); - data[ofs ] = (byte)(value >>> 24); + + public final static void writeInt32BE(int value, byte[] data, int ofs) { + data[ofs + 3] = (byte) (value); + data[ofs + 2] = (byte) (value >>> 8); + data[ofs + 1] = (byte) (value >>> 16); + data[ofs] = (byte) (value >>> 24); } - - public static byte[] hexStrToBytes(String hex) - { - int len = hex.length(); - if (1 == (len & 1)) - { - return null; - } - byte[] result = new byte[len >> 1]; - int r = 0; - int pos = 0; - while (pos < len) - { - int nReg = 0; - for (int nI = 0; nI < 2; nI++) - { - nReg <<= 4; - char c = Character.toLowerCase(hex.charAt(pos++)); - if ('0' <= c && '9' >= c) - { - nReg |= c - '0'; - } - else if ('a' <= c && 'f' >= c) - { - nReg |= (c - 'a') + 10; - } - else - { - return null; - } - } - result[r++] = (byte)nReg; - } - return result; + + public static byte[] hexStrToBytes(String hex) { + int len = hex.length(); + if (1 == (len & 1)) { + return null; + } + byte[] result = new byte[len >> 1]; + int r = 0; + int pos = 0; + while (pos < len) { + int nReg = 0; + for (int nI = 0; nI < 2; nI++) { + nReg <<= 4; + char c = Character.toLowerCase(hex.charAt(pos++)); + if ('0' <= c && '9' >= c) { + nReg |= c - '0'; + } else if ('a' <= c && 'f' >= c) { + nReg |= (c - 'a') + 10; + } else { + return null; + } + } + result[r++] = (byte) nReg; + } + return result; + } + + final static char[] HEXTAB = + { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + public static int hexDump( + InputStream is, + PrintStream ps, + int maxRead, + int bytesPerLine) { + int read, chr, i, result; + char[] pad; + StringBuffer left, right; + + if (1 > bytesPerLine) { + bytesPerLine = 1; + } + + left = new StringBuffer(); + right = new StringBuffer(); + + result = 0; + + for (read = 0, i = 0; ; ) { + if (-1 != maxRead) { + if (maxRead <= read) { + break; + } + } + + try { + if (-1 == (chr = is.read())) { + break; + } + } catch (IOException ioe) { + break; + } + + result++; + + if (0 < i++) { + left.append(' '); + } + + left.append(HEXTAB[chr >>> 4]); + left.append(HEXTAB[chr & 0x0f]); + + right.append((chr < ' ') ? '.' : (char) chr); + + if (0 == (i % bytesPerLine)) { + ps.print(left.toString()); + ps.print(" "); + ps.println(right.toString()); + + left.setLength(0); + right.setLength(0); + + i = 0; + } + } + + if (0 < i) { + pad = new char[((bytesPerLine - i) * 3) + 4]; + Arrays.fill(pad, ' '); + + ps.print(left.toString()); + ps.print(pad); + ps.println(right.toString()); + } + + return result; } - - final static char[] HEXTAB = - { - '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' - }; - - public static int hexDump( - InputStream is, - PrintStream ps, - int maxRead, - int bytesPerLine) - { - int read, chr, i, result; - char[] pad; - StringBuffer left, right; - - - if (1 > bytesPerLine) - { - bytesPerLine = 1; - } - - left = new StringBuffer(); - right = new StringBuffer(); - - result = 0; - - for (read = 0, i = 0;;) - { - if (-1 != maxRead) - { - if (maxRead <= read) - { - break; - } - } - - try - { - if (-1 == (chr = is.read())) - { - break; - } - } - catch (IOException ioe) - { - break; - } - - result++; - - if (0 < i++) - { - left.append(' '); - } - - left.append(HEXTAB[chr >>> 4]); - left.append(HEXTAB[chr & 0x0f]); - - right.append((chr < ' ') ? '.' : (char)chr); - - if (0 == (i % bytesPerLine)) - { - ps.print(left.toString()); - ps.print(" "); - ps.println(right.toString()); - - left.setLength(0); - right.setLength(0); - - i = 0; - } - } - - if (0 < i) - { - pad = new char[((bytesPerLine - i) * 3) + 4]; - Arrays.fill(pad, ' '); - - ps.print(left.toString()); - ps.print(pad); - ps.println(right.toString()); - } - - return result; - } - - public static byte[] swapByteOrder32(byte[] data, int ofs, int len) - { - int end = ofs + len; - byte tmp; - - for (; ofs < end; ofs += 4) - { - tmp = data[ofs]; - data[ofs] = data[ofs + 3]; - data[ofs + 3] = tmp; - - tmp = data[ofs + 1]; - data[ofs + 1] = data[ofs + 2]; - data[ofs + 2] = tmp; - } - return data; + + public static byte[] swapByteOrder32(byte[] data, int ofs, int len) { + int end = ofs + len; + byte tmp; + + for (; ofs < end; ofs += 4) { + tmp = data[ofs]; + data[ofs] = data[ofs + 3]; + data[ofs + 3] = tmp; + + tmp = data[ofs + 1]; + data[ofs + 1] = data[ofs + 2]; + data[ofs + 2] = tmp; + } + return data; } } diff --git a/Safe/src/org/openintents/intents/CryptoIntents.java b/Safe/src/org/openintents/intents/CryptoIntents.java index 646e0ede..b59b4a6f 100644 --- a/Safe/src/org/openintents/intents/CryptoIntents.java +++ b/Safe/src/org/openintents/intents/CryptoIntents.java @@ -16,166 +16,164 @@ package org.openintents.intents; /** - * @version 1.1.1 - * * @author Isaac Potoczny-Jones * @author Peli - * + * @version 1.1.1 */ public class CryptoIntents { - /** - * Activity Action: Encrypt all strings given in the extra(s) EXTRA_TEXT or - * EXTRA_TEXT_ARRAY. - * - * If a file URI is given, the file is encrypted. - * The new file URI is returned. - * - * If the extra EXTRA_SESSION_KEY is provided, the session key is returned, - * and the content URI is returned in the data field. - * - * Returns all encrypted string in the same extra(s). - * - *

Constant Value: "org.openintents.action.ENCRYPT"

- */ - public static final String ACTION_ENCRYPT = "org.openintents.action.ENCRYPT"; - - /** - * Activity Action: Decrypt all strings given in the extra TEXT or - * EXTRA_TEXT_ARRAY. - * - * If a file URI is given, the file is decrypted. - * The new file URI is returned. - * - * If the extra EXTRA_SESSION_KEY is provided, the session key is returned, - * and the content URI is returned in the data field. - * - * Returns all decrypted string in the same extra(s). - * - *

Constant Value: "org.openintents.action.DECRYPT"

- */ - public static final String ACTION_DECRYPT = "org.openintents.action.DECRYPT"; - - /** - * Activity Action: Get the password corresponding to the category of the - * calling application, and the EXTRA_DESCRIPTION, as provided. - * Returns the decrypted username & password in the extras EXTRA_USERNAME and - * EXTRA_PASSWORD. CATEGORY is an optional parameter. - * - *

Constant Value: "org.openintents.action.GET_PASSWORD"

- */ - public static final String ACTION_GET_PASSWORD = "org.openintents.action.GET_PASSWORD"; - - /** - * Activity Action: Set the password corresponding to the category of the - * calling application, and the EXTRA_DESCRIPTION, EXTRA_USERNAME and - * EXTRA_PASSWORD as provided. CATEGORY is an optional parameter. - * - * If both username and password are the non-null empty string, delete this - * password entry. - *

Constant Value: "org.openintents.action.SET_PASSWORD"

- */ - public static final String ACTION_SET_PASSWORD = "org.openintents.action.SET_PASSWORD"; - - /** - * Activity Action: Restarts the timer for the Crypto intent service. - * The timer gets reset when using GET or set password anyway, but this is - * a way to reset the timer for other kinds of actions. Use sparingly since - * we do actually want the timer to time out eventually! - * - *

Constant Value: "org.openintents.action.RESTART_TIMER"

- */ - public static final String ACTION_RESTART_TIMER = "org.openintents.action.RESTART_TIMER"; - - /** - * Broadcast Action: Sent when the user got logged out of the - * crypto session. - * - * This can happen after the user logs out actively, - * or through a time-out. - * - * Activities that show decrypted content should hide that content again. - * - *

Constant Value: "org.openintents.action.CRYPTO_LOGGED_OUT"

- */ - public static final String ACTION_CRYPTO_LOGGED_OUT = "org.openintents.action.CRYPTO_LOGGED_OUT"; - - /** - * Activity Action: Initiate automatic locking of the safe. - * This is used internally from any activity to launch the lock screen. - * - *

Constant Value: "org.openintents.action.AUTOLOCK"

- */ - public static final String ACTION_AUTOLOCK = "org.openintents.action.AUTOLOCK"; - - /** - * The text to encrypt or decrypt, or the location for the return result. - * - *

Constant Value: "org.openintents.extra.TEXT"

- */ - public static final String EXTRA_TEXT = "org.openintents.extra.TEXT"; - - /** - * An array of text to encrypt or decrypt, or the location for the return result. - * Use this to encrypt several strings at once. - * - * Entries of the array that are null will be simply ignored and not - * encrypted or decrypted. - * - *

Constant Value: "org.openintents.extra.TEXT_ARRAY"

- */ - public static final String EXTRA_TEXT_ARRAY = "org.openintents.extra.TEXT_ARRAY"; - - /** - * A session key for encryption or decryption through a content provider. - * - * Include this extra with non-empty value to the ENCRYPT or DECRYPT action, - * and the resulting intent will contain the current session key, valid until - * OI Safe logs out, and the content URI as data. - * - *

Constant Value: "org.openintents.extra.SESSION_KEY"

- */ - public static final String EXTRA_SESSION_KEY = "org.openintents.extra.SESSION_KEY"; - - /** - * Required input parameter to GET_PASSWORD and SET_PASSWORD. Corresponds to the "description" - * field in passwordsafe. Should be a unique name for the password you're using, - * and will already be specific to your application, ie "org.syntaxpolice.opensocial" - * - *

Constant Value: "org.openintents.extra.UNIQUE_NAME"

- */ - public static final String EXTRA_UNIQUE_NAME = "org.openintents.extra.UNIQUE_NAME"; - - /** - * Output parameter from GET_PASSWORD and optional input parameter to SET_PASSWORD. - * Corresponds to the decrypted "username" field in passwordsafe. - * - *

Constant Value: "org.openintents.extra.USERNAME"

- */ - public static final String EXTRA_USERNAME = "org.openintents.extra.USERNAME"; - - /** - * Output parameter from GET_PASSWORD and _required_ input parameter to SET_PASSWORD. - * Corresponds to the decrypted "password" field in passwordsafe. - * - *

Constant Value: "org.openintents.extra.PASSWORD"

- */ - public static final String EXTRA_PASSWORD = "org.openintents.extra.PASSWORD"; - - /** - * Whether to prompt for the password if the service is not running yet. - * - * Default value is 'true'. Set to 'false' if you want to suppress prompting for - * a password. - * - *

Constant Value: "org.openintents.extra.PROMPT"

- */ - public static final String EXTRA_PROMPT = "org.openintents.extra.PROMPT"; - - /** - * Set if the activity handles encrypted content. - * - *

Constant Value: "org.openintents.category.SAFE"

- */ - public static final String CATEGORY_SAFE = "org.openintents.category.SAFE"; + /** + * Activity Action: Encrypt all strings given in the extra(s) EXTRA_TEXT or + * EXTRA_TEXT_ARRAY. + *

+ * If a file URI is given, the file is encrypted. + * The new file URI is returned. + *

+ * If the extra EXTRA_SESSION_KEY is provided, the session key is returned, + * and the content URI is returned in the data field. + *

+ * Returns all encrypted string in the same extra(s). + *

+ *

Constant Value: "org.openintents.action.ENCRYPT"

+ */ + public static final String ACTION_ENCRYPT = "org.openintents.action.ENCRYPT"; + + /** + * Activity Action: Decrypt all strings given in the extra TEXT or + * EXTRA_TEXT_ARRAY. + *

+ * If a file URI is given, the file is decrypted. + * The new file URI is returned. + *

+ * If the extra EXTRA_SESSION_KEY is provided, the session key is returned, + * and the content URI is returned in the data field. + *

+ * Returns all decrypted string in the same extra(s). + *

+ *

Constant Value: "org.openintents.action.DECRYPT"

+ */ + public static final String ACTION_DECRYPT = "org.openintents.action.DECRYPT"; + + /** + * Activity Action: Get the password corresponding to the category of the + * calling application, and the EXTRA_DESCRIPTION, as provided. + * Returns the decrypted username & password in the extras EXTRA_USERNAME and + * EXTRA_PASSWORD. CATEGORY is an optional parameter. + *

+ *

Constant Value: "org.openintents.action.GET_PASSWORD"

+ */ + public static final String ACTION_GET_PASSWORD = "org.openintents.action.GET_PASSWORD"; + + /** + * Activity Action: Set the password corresponding to the category of the + * calling application, and the EXTRA_DESCRIPTION, EXTRA_USERNAME and + * EXTRA_PASSWORD as provided. CATEGORY is an optional parameter. + *

+ * If both username and password are the non-null empty string, delete this + * password entry. + *

Constant Value: "org.openintents.action.SET_PASSWORD"

+ */ + public static final String ACTION_SET_PASSWORD = "org.openintents.action.SET_PASSWORD"; + + /** + * Activity Action: Restarts the timer for the Crypto intent service. + * The timer gets reset when using GET or set password anyway, but this is + * a way to reset the timer for other kinds of actions. Use sparingly since + * we do actually want the timer to time out eventually! + *

+ *

Constant Value: "org.openintents.action.RESTART_TIMER"

+ */ + public static final String ACTION_RESTART_TIMER = "org.openintents.action.RESTART_TIMER"; + + /** + * Broadcast Action: Sent when the user got logged out of the + * crypto session. + *

+ * This can happen after the user logs out actively, + * or through a time-out. + *

+ * Activities that show decrypted content should hide that content again. + *

+ *

Constant Value: "org.openintents.action.CRYPTO_LOGGED_OUT"

+ */ + public static final String ACTION_CRYPTO_LOGGED_OUT = "org.openintents.action.CRYPTO_LOGGED_OUT"; + + /** + * Activity Action: Initiate automatic locking of the safe. + * This is used internally from any activity to launch the lock screen. + *

+ *

Constant Value: "org.openintents.action.AUTOLOCK"

+ */ + public static final String ACTION_AUTOLOCK = "org.openintents.action.AUTOLOCK"; + + /** + * The text to encrypt or decrypt, or the location for the return result. + *

+ *

Constant Value: "org.openintents.extra.TEXT"

+ */ + public static final String EXTRA_TEXT = "org.openintents.extra.TEXT"; + + /** + * An array of text to encrypt or decrypt, or the location for the return result. + * Use this to encrypt several strings at once. + *

+ * Entries of the array that are null will be simply ignored and not + * encrypted or decrypted. + *

+ *

Constant Value: "org.openintents.extra.TEXT_ARRAY"

+ */ + public static final String EXTRA_TEXT_ARRAY = "org.openintents.extra.TEXT_ARRAY"; + + /** + * A session key for encryption or decryption through a content provider. + *

+ * Include this extra with non-empty value to the ENCRYPT or DECRYPT action, + * and the resulting intent will contain the current session key, valid until + * OI Safe logs out, and the content URI as data. + *

+ *

Constant Value: "org.openintents.extra.SESSION_KEY"

+ */ + public static final String EXTRA_SESSION_KEY = "org.openintents.extra.SESSION_KEY"; + + /** + * Required input parameter to GET_PASSWORD and SET_PASSWORD. Corresponds to the "description" + * field in passwordsafe. Should be a unique name for the password you're using, + * and will already be specific to your application, ie "org.syntaxpolice.opensocial" + *

+ *

Constant Value: "org.openintents.extra.UNIQUE_NAME"

+ */ + public static final String EXTRA_UNIQUE_NAME = "org.openintents.extra.UNIQUE_NAME"; + + /** + * Output parameter from GET_PASSWORD and optional input parameter to SET_PASSWORD. + * Corresponds to the decrypted "username" field in passwordsafe. + *

+ *

Constant Value: "org.openintents.extra.USERNAME"

+ */ + public static final String EXTRA_USERNAME = "org.openintents.extra.USERNAME"; + + /** + * Output parameter from GET_PASSWORD and _required_ input parameter to SET_PASSWORD. + * Corresponds to the decrypted "password" field in passwordsafe. + *

+ *

Constant Value: "org.openintents.extra.PASSWORD"

+ */ + public static final String EXTRA_PASSWORD = "org.openintents.extra.PASSWORD"; + + /** + * Whether to prompt for the password if the service is not running yet. + *

+ * Default value is 'true'. Set to 'false' if you want to suppress prompting for + * a password. + *

+ *

Constant Value: "org.openintents.extra.PROMPT"

+ */ + public static final String EXTRA_PROMPT = "org.openintents.extra.PROMPT"; + + /** + * Set if the activity handles encrypted content. + *

+ *

Constant Value: "org.openintents.category.SAFE"

+ */ + public static final String CATEGORY_SAFE = "org.openintents.category.SAFE"; } diff --git a/Safe/src/org/openintents/intents/FileManagerIntents.java b/Safe/src/org/openintents/intents/FileManagerIntents.java index cb7e5353..31670585 100644 --- a/Safe/src/org/openintents/intents/FileManagerIntents.java +++ b/Safe/src/org/openintents/intents/FileManagerIntents.java @@ -18,49 +18,48 @@ // Version Dec 9, 2008 - /** - * Provides OpenIntents actions, extras, and categories used by providers. + * Provides OpenIntents actions, extras, and categories used by providers. *

These specifiers extend the standard Android specifiers.

*/ public final class FileManagerIntents { - /** - * Activity Action: Pick a file through the file manager, or let user - * specify a custom file name. - * Data is the current file name or file name suggestion. - * Returns a new file name as file URI in data. - * - *

Constant Value: "org.openintents.action.PICK_FILE"

- */ - public static final String ACTION_PICK_FILE = "org.openintents.action.PICK_FILE"; + /** + * Activity Action: Pick a file through the file manager, or let user + * specify a custom file name. + * Data is the current file name or file name suggestion. + * Returns a new file name as file URI in data. + *

+ *

Constant Value: "org.openintents.action.PICK_FILE"

+ */ + public static final String ACTION_PICK_FILE = "org.openintents.action.PICK_FILE"; + + /** + * Activity Action: Pick a directory through the file manager, or let user + * specify a custom file name. + * Data is the current directory name or directory name suggestion. + * Returns a new directory name as file URI in data. + *

+ *

Constant Value: "org.openintents.action.PICK_DIRECTORY"

+ */ + public static final String ACTION_PICK_DIRECTORY = "org.openintents.action.PICK_DIRECTORY"; - /** - * Activity Action: Pick a directory through the file manager, or let user - * specify a custom file name. - * Data is the current directory name or directory name suggestion. - * Returns a new directory name as file URI in data. - * - *

Constant Value: "org.openintents.action.PICK_DIRECTORY"

- */ - public static final String ACTION_PICK_DIRECTORY = "org.openintents.action.PICK_DIRECTORY"; - - /** - * The title to display. - * - *

This is shown in the title bar of the file manager.

- * - *

Constant Value: "org.openintents.extra.TITLE"

- */ - public static final String EXTRA_TITLE = "org.openintents.extra.TITLE"; + /** + * The title to display. + *

+ *

This is shown in the title bar of the file manager.

+ *

+ *

Constant Value: "org.openintents.extra.TITLE"

+ */ + public static final String EXTRA_TITLE = "org.openintents.extra.TITLE"; - /** - * The text on the button to display. - * - *

Depending on the use, it makes sense to set this to "Open" or "Save".

- * - *

Constant Value: "org.openintents.extra.BUTTON_TEXT"

- */ - public static final String EXTRA_BUTTON_TEXT = "org.openintents.extra.BUTTON_TEXT"; + /** + * The text on the button to display. + *

+ *

Depending on the use, it makes sense to set this to "Open" or "Save".

+ *

+ *

Constant Value: "org.openintents.extra.BUTTON_TEXT"

+ */ + public static final String EXTRA_BUTTON_TEXT = "org.openintents.extra.BUTTON_TEXT"; } diff --git a/Safe/src/org/openintents/safe/AskPassword.java b/Safe/src/org/openintents/safe/AskPassword.java index 3cf42d12..9fdfe766 100644 --- a/Safe/src/org/openintents/safe/AskPassword.java +++ b/Safe/src/org/openintents/safe/AskPassword.java @@ -16,16 +16,6 @@ */ package org.openintents.safe; -import java.io.File; -import java.security.NoSuchAlgorithmException; - -import org.openintents.distribution.DistributionLibraryActivity; -import org.openintents.safe.password.Master; -import org.openintents.safe.service.AutoLockService; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.honeycomb.WrapActionBar; -import org.openintents.util.VersionUtils; - import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; @@ -50,664 +40,779 @@ import android.widget.TextView; import android.widget.Toast; +import java.io.File; +import java.security.NoSuchAlgorithmException; + +import org.openintents.distribution.DistributionLibraryActivity; +import org.openintents.safe.password.Master; +import org.openintents.safe.service.AutoLockService; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.honeycomb.WrapActionBar; +import org.openintents.util.VersionUtils; + /** * AskPassword Activity - * + *

* This activity just acts as a splash screen and gets the password from the * user that will be used to decrypt/encrypt password entries. - * + * * @author Steven Osborn - http://steven.bitsetters.com */ public class AskPassword extends DistributionLibraryActivity { - private final static boolean debug = false; - private static String TAG = "AskPassword"; - public static String EXTRA_IS_LOCAL = "org.openintents.safe.bundle.EXTRA_IS_REMOTE"; - - public static final int REQUEST_RESTORE = 0; - public static final int REQUEST_RESTORE_FIRST_TIME = 1; - - // Menu Item order - public static final int SWITCH_MODE_INDEX = Menu.FIRST; - public static final int MUTE_INDEX = Menu.FIRST + 1; - private static final int MENU_DISTRIBUTION_START = Menu.FIRST + 100; // MUST BE LAST - - private static final int DIALOG_DISTRIBUTION_START = 100; // MUST BE LAST - - public static final int VIEW_NORMAL = 0; - public static final int VIEW_KEYPAD = 1; - - private int viewMode = VIEW_NORMAL; - - private EditText pbeKey; - private DBHelper dbHelper=null; - private TextView introText; -// private TextView confirmText; - private TextView remoteAsk; - private EditText confirmPass; - private String PBEKey; - private String dbSalt; - private String dbMasterKey; - private CryptoHelper ch; - private boolean firstTime = false; - - // Keypad variables - private String keypadPassword=""; - - private MediaPlayer mpDigitBeep = null; - private MediaPlayer mpErrorBeep = null; - private MediaPlayer mpSuccessBeep = null; - private boolean mute=false; - - private Toast blankPasswordToast = null; - private Toast invalidPasswordToast = null; - private Toast confirmPasswordFailToast = null; - - /** Called when the activity is first created. */ - @SuppressLint("ShowToast") @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mDistribution.setFirst(MENU_DISTRIBUTION_START, DIALOG_DISTRIBUTION_START); - - // Check whether EULA has been accepted - // or information about new version can be presented. - if (mDistribution.showEulaOrNewVersion()) { - return; - } - - if (debug) Log.d(TAG,"onCreate("+icicle+")"); - - dbHelper = new DBHelper(this); - if (dbHelper.isDatabaseOpen()==false) { - Dialog dbError = new AlertDialog.Builder(this) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.database_error_title) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - finish(); - } - }) - .setMessage(R.string.database_error_msg) - .create(); - dbError.show(); - return; - } - - ch = new CryptoHelper(); - if (dbHelper.needsUpgrade()) { - switch (dbHelper.fetchVersion()) { - case 2: - databaseVersionError(); - } - } - dbSalt = dbHelper.fetchSalt(); - dbMasterKey = dbHelper.fetchMasterKey(); - - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - boolean prefKeypad = sp.getBoolean(Preferences.PREFERENCE_KEYPAD, false); - boolean prefKeypadMute = sp.getBoolean(Preferences.PREFERENCE_KEYPAD_MUTE, false); - mute=prefKeypadMute; - - if (prefKeypad) { - viewMode=VIEW_KEYPAD; - } - if (dbMasterKey.length() == 0) { - firstTime=true; - } - if ((viewMode==VIEW_NORMAL) || (firstTime)) { - normalInit(); - } else { - keypadInit(); - } - - blankPasswordToast = Toast.makeText(AskPassword.this, R.string.notify_blank_pass, Toast.LENGTH_SHORT); - invalidPasswordToast = Toast.makeText(AskPassword.this, R.string.invalid_password, Toast.LENGTH_SHORT); - confirmPasswordFailToast = Toast.makeText(AskPassword.this, R.string.confirm_pass_fail, Toast.LENGTH_SHORT); - } - - private void normalInit() { - // Setup layout - setContentView(R.layout.front_door); - TextView header = (TextView) findViewById(R.id.entry_header); - String version = VersionUtils.getVersionNumber(this); - String appName = VersionUtils.getApplicationName(this); - String head = appName + " " + version; - header.setText(head); - - Intent thisIntent = getIntent(); - boolean isLocal = thisIntent.getBooleanExtra (EXTRA_IS_LOCAL, false); - - pbeKey = (EditText) findViewById(R.id.password); - pbeKey.requestFocus(); - pbeKey.postDelayed(new Runnable() { - public void run() { - InputMethodManager keyboard = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); - keyboard.showSoftInput(pbeKey, 0); - } - }, 200); - introText = (TextView) findViewById(R.id.first_time); - remoteAsk = (TextView) findViewById(R.id.remote); - confirmPass = (EditText) findViewById(R.id.pass_confirm); + private final static boolean debug = false; + private static String TAG = "AskPassword"; + public static String EXTRA_IS_LOCAL = "org.openintents.safe.bundle.EXTRA_IS_REMOTE"; + + public static final int REQUEST_RESTORE = 0; + public static final int REQUEST_RESTORE_FIRST_TIME = 1; + + // Menu Item order + public static final int SWITCH_MODE_INDEX = Menu.FIRST; + public static final int MUTE_INDEX = Menu.FIRST + 1; + private static final int MENU_DISTRIBUTION_START = Menu.FIRST + 100; // MUST BE LAST + + private static final int DIALOG_DISTRIBUTION_START = 100; // MUST BE LAST + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_KEYPAD = 1; + + private int viewMode = VIEW_NORMAL; + + private EditText pbeKey; + private DBHelper dbHelper = null; + private TextView introText; + // private TextView confirmText; + private TextView remoteAsk; + private EditText confirmPass; + private String PBEKey; + private String dbSalt; + private String dbMasterKey; + private CryptoHelper ch; + private boolean firstTime = false; + + // Keypad variables + private String keypadPassword = ""; + + private MediaPlayer mpDigitBeep = null; + private MediaPlayer mpErrorBeep = null; + private MediaPlayer mpSuccessBeep = null; + private boolean mute = false; + + private Toast blankPasswordToast = null; + private Toast invalidPasswordToast = null; + private Toast confirmPasswordFailToast = null; + + /** + * Called when the activity is first created. + */ + @SuppressLint("ShowToast") + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mDistribution.setFirst(MENU_DISTRIBUTION_START, DIALOG_DISTRIBUTION_START); + + // Check whether EULA has been accepted + // or information about new version can be presented. + if (mDistribution.showEulaOrNewVersion()) { + return; + } + + if (debug) { + Log.d(TAG, "onCreate(" + icicle + ")"); + } + + dbHelper = new DBHelper(this); + if (dbHelper.isDatabaseOpen() == false) { + Dialog dbError = new AlertDialog.Builder(this) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.database_error_title) + .setPositiveButton( + android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + finish(); + } + } + ) + .setMessage(R.string.database_error_msg) + .create(); + dbError.show(); + return; + } + + ch = new CryptoHelper(); + if (dbHelper.needsUpgrade()) { + switch (dbHelper.fetchVersion()) { + case 2: + databaseVersionError(); + } + } + dbSalt = dbHelper.fetchSalt(); + dbMasterKey = dbHelper.fetchMasterKey(); + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + boolean prefKeypad = sp.getBoolean(Preferences.PREFERENCE_KEYPAD, false); + boolean prefKeypadMute = sp.getBoolean(Preferences.PREFERENCE_KEYPAD_MUTE, false); + mute = prefKeypadMute; + + if (prefKeypad) { + viewMode = VIEW_KEYPAD; + } + if (dbMasterKey.length() == 0) { + firstTime = true; + } + if ((viewMode == VIEW_NORMAL) || (firstTime)) { + normalInit(); + } else { + keypadInit(); + } + + blankPasswordToast = Toast.makeText(AskPassword.this, R.string.notify_blank_pass, Toast.LENGTH_SHORT); + invalidPasswordToast = Toast.makeText(AskPassword.this, R.string.invalid_password, Toast.LENGTH_SHORT); + confirmPasswordFailToast = Toast.makeText(AskPassword.this, R.string.confirm_pass_fail, Toast.LENGTH_SHORT); + } + + private void normalInit() { + // Setup layout + setContentView(R.layout.front_door); + TextView header = (TextView) findViewById(R.id.entry_header); + String version = VersionUtils.getVersionNumber(this); + String appName = VersionUtils.getApplicationName(this); + String head = appName + " " + version; + header.setText(head); + + Intent thisIntent = getIntent(); + boolean isLocal = thisIntent.getBooleanExtra(EXTRA_IS_LOCAL, false); + + pbeKey = (EditText) findViewById(R.id.password); + pbeKey.requestFocus(); + pbeKey.postDelayed( + new Runnable() { + public void run() { + InputMethodManager keyboard = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + keyboard.showSoftInput(pbeKey, 0); + } + }, 200 + ); + introText = (TextView) findViewById(R.id.first_time); + remoteAsk = (TextView) findViewById(R.id.remote); + confirmPass = (EditText) findViewById(R.id.pass_confirm); // confirmText = (TextView) findViewById(R.id.confirm_lbl); - if (dbMasterKey.length() == 0) { - firstTime = true; - introText.setVisibility(View.VISIBLE); + if (dbMasterKey.length() == 0) { + firstTime = true; + introText.setVisibility(View.VISIBLE); // confirmText.setVisibility(View.VISIBLE); - confirmPass.setVisibility(View.VISIBLE); - checkForBackup(); - } - if (! isLocal) { - if (remoteAsk != null) { - remoteAsk.setVisibility(View.VISIBLE); - } - } - if (firstTime) { - confirmPass.setOnEditorActionListener(new TextView.OnEditorActionListener() { - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_DONE) { - handleContinue(); - return true; - } - return false; - } - }); - }else{ - pbeKey.setOnEditorActionListener(new TextView.OnEditorActionListener() { - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_DONE) { - handleContinue(); - return true; - } - return false; - } - }); - } - Button continueButton = (Button) findViewById(R.id.continue_button); - - continueButton.setOnClickListener(new View.OnClickListener() { - - public void onClick(View arg0) { - handleContinue(); - } - }); - } - - private void handleContinue() { - PBEKey = pbeKey.getText().toString(); - // For this version of CryptoHelper, we use the user-entered password. - // All other versions should be instantiated with the generated master - // password. - - // Password must be at least 4 characters - if (PBEKey.length() < 4) { - pbeKey.setText(""); - confirmPass.setText(""); - pbeKey.requestFocus(); - blankPasswordToast.show(); - Animation shake = AnimationUtils - .loadAnimation(AskPassword.this, R.anim.shake); - - findViewById(R.id.password).startAnimation(shake); - return; - } - - // If it's the user's first time to enter a password, - // we have to store it in the database. We are going to - // store an encrypted hash of the password. - // Generate a master key, encrypt that with the pbekey - // and store the encrypted master key in database. - if (firstTime) { - - // Make sure password and confirm fields match - if (pbeKey.getText().toString().compareTo( - confirmPass.getText().toString()) != 0) { - confirmPass.setText(""); - confirmPasswordFailToast.show(); - Animation shake = AnimationUtils - .loadAnimation(AskPassword.this, R.anim.shake); - - findViewById(R.id.password).startAnimation(shake); - return; - } - try { - dbSalt = CryptoHelper.generateSalt(); - dbMasterKey = CryptoHelper.generateMasterKey(); - } catch (NoSuchAlgorithmException e1) { - e1.printStackTrace(); - Toast.makeText(AskPassword.this,getString(R.string.crypto_error) - + e1.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - if (debug) Log.i(TAG, "Saving Password: " + dbMasterKey); - try { - ch.init(CryptoHelper.EncryptionStrong,dbSalt); - ch.setPassword(PBEKey); - String encryptedMasterKey = ch.encrypt(dbMasterKey); - dbHelper.storeSalt(dbSalt); - dbHelper.storeMasterKey(encryptedMasterKey); - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString()); - Toast.makeText(AskPassword.this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - } else if (!checkUserPassword(PBEKey)) { - // Check the user's password and display a - // message if it's wrong - pbeKey.setText(""); - invalidPasswordToast.show(); - Animation shake = AnimationUtils - .loadAnimation(AskPassword.this, R.anim.shake); - - findViewById(R.id.password).startAnimation(shake); - return; - } - gotPassword(); - } - - private void gotPassword() { - Intent callbackIntent = new Intent(); - - // We no longer need the - // user-entered PBEKey. The master key is used for everything - // from here on out. - if (debug) Log.d(TAG,"got password"); - setResult(RESULT_OK, callbackIntent); - - Master.setMasterKey(dbMasterKey); - Master.setSalt(dbSalt); - - if (debug) Log.d(TAG,"start AutoLockService"); - Intent myIntent = new Intent(getApplicationContext(), AutoLockService.class); - startService(myIntent); - - CryptoContentProvider.ch = ch; - finish(); - } - - private void checkForBackup() { - String backupFullname=Preferences.getBackupPath(this); - File restoreFile=new File(backupFullname); - if (!restoreFile.exists()) { - return; - } - startActivityForResult(new Intent(this, RestoreFirstTime.class), REQUEST_RESTORE_FIRST_TIME); - } - - @Override - protected void onPause() { - super.onPause(); - - if (debug) Log.d(TAG, "onPause()"); - - if (blankPasswordToast != null) - blankPasswordToast.cancel(); - if (invalidPasswordToast != null) - invalidPasswordToast.cancel(); - if (confirmPasswordFailToast != null) - confirmPasswordFailToast.cancel(); - - if (dbHelper!=null) { - dbHelper.close(); - dbHelper = null; - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - - if (debug) Log.d(TAG,"onDestroy()"); - keypadOnDestroy(); - } - - @Override - protected void onResume() { - super.onPause(); - - if (debug) Log.d(TAG, "onResume()"); - if (CategoryList.isSignedIn()==true) { - if (debug) Log.d(TAG,"already signed in"); - Intent callbackIntent = new Intent(); - setResult(RESULT_OK, callbackIntent); - finish(); - return; - } - - if (dbHelper == null) { - dbHelper = new DBHelper(this); - } - if (dbHelper.isDatabaseOpen()==false) { - if (debug) Log.d(TAG, "eek! database is not open"); - return; - } - if (viewMode==VIEW_NORMAL) { - // clear pbeKey in case user had typed it, strayed - // to something else, then another person opened - // the app. Wouldn't want the password already typed - pbeKey.setText(""); - } - - } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - if (menu != null) { - MenuItem miSwitch = menu.findItem(SWITCH_MODE_INDEX); - if (firstTime) { - miSwitch.setEnabled(false); - } else { - miSwitch.setEnabled(true); - } - MenuItem miMute = menu.findItem(MUTE_INDEX); - if (viewMode==VIEW_KEYPAD) { - miMute.setVisible(true); - if (mute) { - miMute.setTitle(R.string.sounds); - miMute.setIcon(android.R.drawable.ic_lock_silent_mode_off); - } else { - miMute.setTitle(R.string.mute); - miMute.setIcon(android.R.drawable.ic_lock_silent_mode); - } - } else { - miMute.setVisible(false); - } - } - return super.onMenuOpened(featureId, menu); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem item = menu.add(0, SWITCH_MODE_INDEX, 0, R.string.switch_mode); - // icon set below in onPrepareOptionsMenu() - if (CheckWrappers.mActionBarAvailable) { - WrapActionBar.showIfRoom(item); - } - if (firstTime) { - item.setEnabled(false); - } else { - item.setEnabled(true); - } - - MenuItem miMute; - if (mute) { - miMute=menu.add(0, MUTE_INDEX, 0, R.string.sounds) - .setIcon(android.R.drawable.ic_lock_silent_mode_off); - } else { - miMute=menu.add(0, MUTE_INDEX, 0, R.string.mute) - .setIcon(android.R.drawable.ic_lock_silent_mode); - } - miMute.setVisible(viewMode==VIEW_KEYPAD); - - // Add distribution menu items last. - mDistribution.onCreateOptionsMenu(menu); - - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - - MenuItem item = menu.findItem(SWITCH_MODE_INDEX); - if (CheckWrappers.mActionBarAvailable) { - if (viewMode==VIEW_NORMAL) { - item.setIcon(R.drawable.ic_menu_switch_numeric); - } else { // viewMode==VIEW_KEYPAD - item.setIcon(R.drawable.ic_menu_switch_alpha); - } - } else { - item.setIcon(android.R.drawable.ic_menu_directions); - } - - return true; - } - - private void switchView() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - SharedPreferences.Editor spe=sp.edit(); - if (viewMode==VIEW_NORMAL) { - viewMode=VIEW_KEYPAD; - spe.putBoolean(Preferences.PREFERENCE_KEYPAD, true); - keypadInit(); - } else { - viewMode=VIEW_NORMAL; - spe.putBoolean(Preferences.PREFERENCE_KEYPAD, false); - normalInit(); - } - if (!spe.commit()) { - if (debug) Log.d(TAG,"commitment issues"); - } - if (CheckWrappers.mActionBarAvailable) { - WrapActionBar.invalidateOptionsMenu(this); - } - } - - public boolean onOptionsItemSelected(MenuItem item) { - switch(item.getItemId()) { - case SWITCH_MODE_INDEX: - switchView(); - break; - case MUTE_INDEX: - SharedPreferences msp = PreferenceManager.getDefaultSharedPreferences(this); - SharedPreferences.Editor mspe=msp.edit(); - mspe.putBoolean(Preferences.PREFERENCE_KEYPAD_MUTE, !mute); - mute=!mute; - if (!mspe.commit()) { - if (debug) Log.d(TAG,"mute commitment issues"); - } - break; - default: - Log.e(TAG,"Unknown itemId"); - break; - } - return super.onOptionsItemSelected(item); - } - - private void databaseVersionError() { - Dialog about = new AlertDialog.Builder(this) - .setIcon(R.drawable.passicon) - .setTitle(R.string.database_version_error_title) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - setResult(RESULT_CANCELED); - finish(); - } - }) - .setMessage(R.string.database_version_error_msg) - .create(); - about.show(); - - } - /** - * - * @return - */ - private boolean checkUserPassword(String password) { - if (dbHelper==null) { - // not sure what can cause this condition, but a NPE has been observed - return false; - } - String encryptedMasterKey = dbHelper.fetchMasterKey(); - String decryptedMasterKey = ""; - if (debug) Log.d(TAG,"checkUserPassword: encryptedMasterKey="+encryptedMasterKey); - try { - ch.init(CryptoHelper.EncryptionStrong,dbSalt); - ch.setPassword(password); - decryptedMasterKey = ch.decrypt(encryptedMasterKey); - if (debug) Log.d(TAG,"decryptedMasterKey="+decryptedMasterKey); - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString()); - } - if (ch.getStatus()==true) { - dbMasterKey=decryptedMasterKey; - return true; - } - return false; - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent i) { - super.onActivityResult(requestCode, resultCode, i); - - if ((requestCode==REQUEST_RESTORE_FIRST_TIME) && (resultCode == RESULT_OK)) { - Intent callbackIntent = new Intent(); - setResult(RESULT_OK, callbackIntent); - finish(); - } - } - - /////////////// Keypad Functions ///////////////////// - - private void keypadInit() { - if (mpDigitBeep==null) { - mpDigitBeep = MediaPlayer.create(this, R.raw.dtmf2a); - mpErrorBeep = MediaPlayer.create(this, R.raw.click6a); - mpSuccessBeep = MediaPlayer.create(this, R.raw.dooropening1); - } - - keypadPassword=""; - - setContentView(R.layout.keypad); - - TextView header = (TextView) findViewById(R.id.entry_header); - String version = VersionUtils.getVersionNumber(this); - String appName = VersionUtils.getApplicationName(this); - String head = appName + " " + version; - header.setText(head); - - Button keypad1 = (Button) findViewById(R.id.keypad1); - keypad1.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "1"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad2 = (Button) findViewById(R.id.keypad2); - keypad2.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "2"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad3 = (Button) findViewById(R.id.keypad3); - keypad3.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "3"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad4 = (Button) findViewById(R.id.keypad4); - keypad4.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "4"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad5 = (Button) findViewById(R.id.keypad5); - keypad5.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "5"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad6 = (Button) findViewById(R.id.keypad6); - keypad6.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "6"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad7 = (Button) findViewById(R.id.keypad7); - keypad7.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "7"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad8 = (Button) findViewById(R.id.keypad8); - keypad8.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "8"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad9 = (Button) findViewById(R.id.keypad9); - keypad9.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "9"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypadStar = (Button) findViewById(R.id.keypad_star); - keypadStar.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "*"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypad0 = (Button) findViewById(R.id.keypad0); - keypad0.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "0"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypadPound = (Button) findViewById(R.id.keypad_pound); - keypadPound.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadPassword += "#"; - if (!mute) { mpDigitBeep.start(); } - } - }); - Button keypadContinue = (Button) findViewById(R.id.keypad_continue); - keypadContinue.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - keypadTryPassword(keypadPassword); - } - }); - ImageView keypadSwitch = (ImageView) findViewById(R.id.switch_button); - keypadSwitch.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - switchView(); - } - }); - if (CheckWrappers.mActionBarAvailable) { - keypadSwitch.setVisibility(View.INVISIBLE); - } - } - - private void keypadOnDestroy() { - if (mpDigitBeep!=null) { - mpDigitBeep.release(); - mpErrorBeep.release(); - mpSuccessBeep.release(); - mpDigitBeep=null; - mpErrorBeep=null; - mpSuccessBeep=null; - } - } - - private void keypadTryPassword(String password) { - if (checkUserPassword(password)){ - if (debug) Log.d(TAG,"match!!"); - if (!mute) { - mpSuccessBeep.start(); - } - gotPassword(); - }else{ - if (debug) Log.d(TAG,"bad password"); - if (!mute) { - mpErrorBeep.start(); - } - Animation shake = AnimationUtils - .loadAnimation(AskPassword.this, R.anim.shake); - findViewById(R.id.keypad_continue).startAnimation(shake); - - keypadPassword=""; - } - } + confirmPass.setVisibility(View.VISIBLE); + checkForBackup(); + } + if (!isLocal) { + if (remoteAsk != null) { + remoteAsk.setVisibility(View.VISIBLE); + } + } + if (firstTime) { + confirmPass.setOnEditorActionListener( + new TextView.OnEditorActionListener() { + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + handleContinue(); + return true; + } + return false; + } + } + ); + } else { + pbeKey.setOnEditorActionListener( + new TextView.OnEditorActionListener() { + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + handleContinue(); + return true; + } + return false; + } + } + ); + } + Button continueButton = (Button) findViewById(R.id.continue_button); + + continueButton.setOnClickListener( + new View.OnClickListener() { + + public void onClick(View arg0) { + handleContinue(); + } + } + ); + } + + private void handleContinue() { + PBEKey = pbeKey.getText().toString(); + // For this version of CryptoHelper, we use the user-entered password. + // All other versions should be instantiated with the generated master + // password. + + // Password must be at least 4 characters + if (PBEKey.length() < 4) { + pbeKey.setText(""); + confirmPass.setText(""); + pbeKey.requestFocus(); + blankPasswordToast.show(); + Animation shake = AnimationUtils + .loadAnimation(AskPassword.this, R.anim.shake); + + findViewById(R.id.password).startAnimation(shake); + return; + } + + // If it's the user's first time to enter a password, + // we have to store it in the database. We are going to + // store an encrypted hash of the password. + // Generate a master key, encrypt that with the pbekey + // and store the encrypted master key in database. + if (firstTime) { + + // Make sure password and confirm fields match + if (pbeKey.getText().toString().compareTo( + confirmPass.getText().toString() + ) != 0) { + confirmPass.setText(""); + confirmPasswordFailToast.show(); + Animation shake = AnimationUtils + .loadAnimation(AskPassword.this, R.anim.shake); + + findViewById(R.id.password).startAnimation(shake); + return; + } + try { + dbSalt = CryptoHelper.generateSalt(); + dbMasterKey = CryptoHelper.generateMasterKey(); + } catch (NoSuchAlgorithmException e1) { + e1.printStackTrace(); + Toast.makeText( + AskPassword.this, getString(R.string.crypto_error) + + e1.getMessage(), Toast.LENGTH_SHORT + ).show(); + return; + } + if (debug) { + Log.i(TAG, "Saving Password: " + dbMasterKey); + } + try { + ch.init(CryptoHelper.EncryptionStrong, dbSalt); + ch.setPassword(PBEKey); + String encryptedMasterKey = ch.encrypt(dbMasterKey); + dbHelper.storeSalt(dbSalt); + dbHelper.storeMasterKey(encryptedMasterKey); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + Toast.makeText( + AskPassword.this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + return; + } + } else if (!checkUserPassword(PBEKey)) { + // Check the user's password and display a + // message if it's wrong + pbeKey.setText(""); + invalidPasswordToast.show(); + Animation shake = AnimationUtils + .loadAnimation(AskPassword.this, R.anim.shake); + + findViewById(R.id.password).startAnimation(shake); + return; + } + gotPassword(); + } + + private void gotPassword() { + Intent callbackIntent = new Intent(); + + // We no longer need the + // user-entered PBEKey. The master key is used for everything + // from here on out. + if (debug) { + Log.d(TAG, "got password"); + } + setResult(RESULT_OK, callbackIntent); + + Master.setMasterKey(dbMasterKey); + Master.setSalt(dbSalt); + + if (debug) { + Log.d(TAG, "start AutoLockService"); + } + Intent myIntent = new Intent(getApplicationContext(), AutoLockService.class); + startService(myIntent); + + CryptoContentProvider.ch = ch; + finish(); + } + + private void checkForBackup() { + String backupFullname = Preferences.getBackupPath(this); + File restoreFile = new File(backupFullname); + if (!restoreFile.exists()) { + return; + } + startActivityForResult(new Intent(this, RestoreFirstTime.class), REQUEST_RESTORE_FIRST_TIME); + } + + @Override + protected void onPause() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onPause()"); + } + + if (blankPasswordToast != null) { + blankPasswordToast.cancel(); + } + if (invalidPasswordToast != null) { + invalidPasswordToast.cancel(); + } + if (confirmPasswordFailToast != null) { + confirmPasswordFailToast.cancel(); + } + + if (dbHelper != null) { + dbHelper.close(); + dbHelper = null; + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (debug) { + Log.d(TAG, "onDestroy()"); + } + keypadOnDestroy(); + } + + @Override + protected void onResume() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + if (CategoryList.isSignedIn() == true) { + if (debug) { + Log.d(TAG, "already signed in"); + } + Intent callbackIntent = new Intent(); + setResult(RESULT_OK, callbackIntent); + finish(); + return; + } + + if (dbHelper == null) { + dbHelper = new DBHelper(this); + } + if (dbHelper.isDatabaseOpen() == false) { + if (debug) { + Log.d(TAG, "eek! database is not open"); + } + return; + } + if (viewMode == VIEW_NORMAL) { + // clear pbeKey in case user had typed it, strayed + // to something else, then another person opened + // the app. Wouldn't want the password already typed + pbeKey.setText(""); + } + + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + if (menu != null) { + MenuItem miSwitch = menu.findItem(SWITCH_MODE_INDEX); + if (firstTime) { + miSwitch.setEnabled(false); + } else { + miSwitch.setEnabled(true); + } + MenuItem miMute = menu.findItem(MUTE_INDEX); + if (viewMode == VIEW_KEYPAD) { + miMute.setVisible(true); + if (mute) { + miMute.setTitle(R.string.sounds); + miMute.setIcon(android.R.drawable.ic_lock_silent_mode_off); + } else { + miMute.setTitle(R.string.mute); + miMute.setIcon(android.R.drawable.ic_lock_silent_mode); + } + } else { + miMute.setVisible(false); + } + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + MenuItem item = menu.add(0, SWITCH_MODE_INDEX, 0, R.string.switch_mode); + // icon set below in onPrepareOptionsMenu() + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar.showIfRoom(item); + } + if (firstTime) { + item.setEnabled(false); + } else { + item.setEnabled(true); + } + + MenuItem miMute; + if (mute) { + miMute = menu.add(0, MUTE_INDEX, 0, R.string.sounds) + .setIcon(android.R.drawable.ic_lock_silent_mode_off); + } else { + miMute = menu.add(0, MUTE_INDEX, 0, R.string.mute) + .setIcon(android.R.drawable.ic_lock_silent_mode); + } + miMute.setVisible(viewMode == VIEW_KEYPAD); + + // Add distribution menu items last. + mDistribution.onCreateOptionsMenu(menu); + + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + + MenuItem item = menu.findItem(SWITCH_MODE_INDEX); + if (CheckWrappers.mActionBarAvailable) { + if (viewMode == VIEW_NORMAL) { + item.setIcon(R.drawable.ic_menu_switch_numeric); + } else { // viewMode==VIEW_KEYPAD + item.setIcon(R.drawable.ic_menu_switch_alpha); + } + } else { + item.setIcon(android.R.drawable.ic_menu_directions); + } + + return true; + } + + private void switchView() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor spe = sp.edit(); + if (viewMode == VIEW_NORMAL) { + viewMode = VIEW_KEYPAD; + spe.putBoolean(Preferences.PREFERENCE_KEYPAD, true); + keypadInit(); + } else { + viewMode = VIEW_NORMAL; + spe.putBoolean(Preferences.PREFERENCE_KEYPAD, false); + normalInit(); + } + if (!spe.commit()) { + if (debug) { + Log.d(TAG, "commitment issues"); + } + } + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar.invalidateOptionsMenu(this); + } + } + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case SWITCH_MODE_INDEX: + switchView(); + break; + case MUTE_INDEX: + SharedPreferences msp = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor mspe = msp.edit(); + mspe.putBoolean(Preferences.PREFERENCE_KEYPAD_MUTE, !mute); + mute = !mute; + if (!mspe.commit()) { + if (debug) { + Log.d(TAG, "mute commitment issues"); + } + } + break; + default: + Log.e(TAG, "Unknown itemId"); + break; + } + return super.onOptionsItemSelected(item); + } + + private void databaseVersionError() { + Dialog about = new AlertDialog.Builder(this) + .setIcon(R.drawable.passicon) + .setTitle(R.string.database_version_error_title) + .setPositiveButton( + android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + setResult(RESULT_CANCELED); + finish(); + } + } + ) + .setMessage(R.string.database_version_error_msg) + .create(); + about.show(); + + } + + /** + * @return + */ + private boolean checkUserPassword(String password) { + if (dbHelper == null) { + // not sure what can cause this condition, but a NPE has been observed + return false; + } + String encryptedMasterKey = dbHelper.fetchMasterKey(); + String decryptedMasterKey = ""; + if (debug) { + Log.d(TAG, "checkUserPassword: encryptedMasterKey=" + encryptedMasterKey); + } + try { + ch.init(CryptoHelper.EncryptionStrong, dbSalt); + ch.setPassword(password); + decryptedMasterKey = ch.decrypt(encryptedMasterKey); + if (debug) { + Log.d(TAG, "decryptedMasterKey=" + decryptedMasterKey); + } + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + if (ch.getStatus() == true) { + dbMasterKey = decryptedMasterKey; + return true; + } + return false; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + + if ((requestCode == REQUEST_RESTORE_FIRST_TIME) && (resultCode == RESULT_OK)) { + Intent callbackIntent = new Intent(); + setResult(RESULT_OK, callbackIntent); + finish(); + } + } + + /////////////// Keypad Functions ///////////////////// + + private void keypadInit() { + if (mpDigitBeep == null) { + mpDigitBeep = MediaPlayer.create(this, R.raw.dtmf2a); + mpErrorBeep = MediaPlayer.create(this, R.raw.click6a); + mpSuccessBeep = MediaPlayer.create(this, R.raw.dooropening1); + } + + keypadPassword = ""; + + setContentView(R.layout.keypad); + + TextView header = (TextView) findViewById(R.id.entry_header); + String version = VersionUtils.getVersionNumber(this); + String appName = VersionUtils.getApplicationName(this); + String head = appName + " " + version; + header.setText(head); + + Button keypad1 = (Button) findViewById(R.id.keypad1); + keypad1.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "1"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad2 = (Button) findViewById(R.id.keypad2); + keypad2.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "2"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad3 = (Button) findViewById(R.id.keypad3); + keypad3.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "3"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad4 = (Button) findViewById(R.id.keypad4); + keypad4.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "4"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad5 = (Button) findViewById(R.id.keypad5); + keypad5.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "5"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad6 = (Button) findViewById(R.id.keypad6); + keypad6.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "6"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad7 = (Button) findViewById(R.id.keypad7); + keypad7.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "7"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad8 = (Button) findViewById(R.id.keypad8); + keypad8.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "8"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad9 = (Button) findViewById(R.id.keypad9); + keypad9.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "9"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypadStar = (Button) findViewById(R.id.keypad_star); + keypadStar.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "*"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypad0 = (Button) findViewById(R.id.keypad0); + keypad0.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "0"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypadPound = (Button) findViewById(R.id.keypad_pound); + keypadPound.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadPassword += "#"; + if (!mute) { + mpDigitBeep.start(); + } + } + } + ); + Button keypadContinue = (Button) findViewById(R.id.keypad_continue); + keypadContinue.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + keypadTryPassword(keypadPassword); + } + } + ); + ImageView keypadSwitch = (ImageView) findViewById(R.id.switch_button); + keypadSwitch.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + switchView(); + } + } + ); + if (CheckWrappers.mActionBarAvailable) { + keypadSwitch.setVisibility(View.INVISIBLE); + } + } + + private void keypadOnDestroy() { + if (mpDigitBeep != null) { + mpDigitBeep.release(); + mpErrorBeep.release(); + mpSuccessBeep.release(); + mpDigitBeep = null; + mpErrorBeep = null; + mpSuccessBeep = null; + } + } + + private void keypadTryPassword(String password) { + if (checkUserPassword(password)) { + if (debug) { + Log.d(TAG, "match!!"); + } + if (!mute) { + mpSuccessBeep.start(); + } + gotPassword(); + } else { + if (debug) { + Log.d(TAG, "bad password"); + } + if (!mute) { + mpErrorBeep.start(); + } + Animation shake = AnimationUtils + .loadAnimation(AskPassword.this, R.anim.shake); + findViewById(R.id.keypad_continue).startAnimation(shake); + + keypadPassword = ""; + } + } } diff --git a/Safe/src/org/openintents/safe/Backup.java b/Safe/src/org/openintents/safe/Backup.java index 0c975522..c389fabf 100644 --- a/Safe/src/org/openintents/safe/Backup.java +++ b/Safe/src/org/openintents/safe/Backup.java @@ -16,7 +16,13 @@ */ package org.openintents.safe; -import java.io.FileOutputStream; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.text.format.Time; +import android.util.Log; +import android.util.Xml; + import java.io.IOException; import java.io.OutputStream; import java.text.DateFormat; @@ -26,155 +32,155 @@ import java.util.List; import java.util.TimeZone; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.format.Time; -import android.util.Log; -import android.util.Xml; - public class Backup { - private static boolean debug = false; - private static final String TAG = "Backup"; - - public static int CURRENT_VERSION = 1; - - private String result=""; - - Context myCtx=null; - - public Backup(Context ctx) { - myCtx=ctx; - } - - public boolean write(String filename, OutputStream str) { - if (debug) Log.d(TAG,"write("+filename+",)"); - - try { - org.xmlpull.v1.XmlSerializer serializer = Xml.newSerializer(); - serializer.setOutput(str, "utf-8"); - serializer.startDocument(null, Boolean.valueOf(true)); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - serializer.startTag(null, "OISafe"); - - serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION)); - - Date today; - String dateOut; - DateFormat dateFormatter; - - dateFormatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, - DateFormat.FULL); - today = new Date(); - dateOut = dateFormatter.format(today); - - serializer.attribute(null, "date", dateOut); - - String masterKeyEncrypted = Passwords.fetchMasterKeyEncrypted(); - serializer.startTag(null, "MasterKey"); - serializer.text(masterKeyEncrypted); - serializer.endTag(null, "MasterKey"); - - String salt = Passwords.fetchSalt(); - serializer.startTag(null, "Salt"); - serializer.text(salt); - serializer.endTag(null, "Salt"); - - List crows; - crows = Passwords.getCategoryEntries(); - - int totalPasswords=0; - - for (CategoryEntry crow : crows) { - - serializer.startTag(null, "Category"); - serializer.attribute(null, "name", crow.name); - - List rows; - rows = Passwords.getPassEntries(crow.id, false, false); - - for (PassEntry row : rows) { - totalPasswords++; - - serializer.startTag(null, "Entry"); - - serializer.startTag(null, "RowID"); - serializer.text(Long.toString(row.id)); - serializer.endTag(null, "RowID"); - - serializer.startTag(null, "Description"); - serializer.text(row.description); - serializer.endTag(null, "Description"); - - serializer.startTag(null, "Website"); - serializer.text(row.website); - serializer.endTag(null, "Website"); - - serializer.startTag(null, "Username"); - serializer.text(row.username); - serializer.endTag(null, "Username"); - - serializer.startTag(null, "Password"); - serializer.text(row.password); - serializer.endTag(null, "Password"); - - serializer.startTag(null, "Note"); - serializer.text(row.note); - serializer.endTag(null, "Note"); - - if (row.uniqueName!=null) { - serializer.startTag(null, "UniqueName"); - serializer.text(row.uniqueName); - serializer.endTag(null, "UniqueName"); - } - - ArrayList packageAccess=Passwords.getPackageAccessEntries(row.id); - if(packageAccess!=null) { - serializer.startTag(null, "PackageAccess"); - String entry=""; - Iterator packIter=packageAccess.iterator(); - while (packIter.hasNext()) { - if (entry.length()!=0) { - entry += ","; - } - entry += packIter.next().packageAccess; - } - entry = "[" + entry + "]"; - serializer.text(entry); - serializer.endTag(null, "PackageAccess"); - } - - serializer.endTag(null, "Entry"); - } - serializer.endTag(null, "Category"); - } - - serializer.endTag(null, "OISafe"); - serializer.endDocument(); + private static boolean debug = false; + private static final String TAG = "Backup"; + + public static int CURRENT_VERSION = 1; + + private String result = ""; + + Context myCtx = null; + + public Backup(Context ctx) { + myCtx = ctx; + } + + public boolean write(String filename, OutputStream str) { + if (debug) { + Log.d(TAG, "write(" + filename + ",)"); + } + + try { + org.xmlpull.v1.XmlSerializer serializer = Xml.newSerializer(); + serializer.setOutput(str, "utf-8"); + serializer.startDocument(null, Boolean.valueOf(true)); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + serializer.startTag(null, "OISafe"); + + serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION)); + + Date today; + String dateOut; + DateFormat dateFormatter; + + dateFormatter = DateFormat.getDateTimeInstance( + DateFormat.DEFAULT, + DateFormat.FULL + ); + today = new Date(); + dateOut = dateFormatter.format(today); + + serializer.attribute(null, "date", dateOut); + + String masterKeyEncrypted = Passwords.fetchMasterKeyEncrypted(); + serializer.startTag(null, "MasterKey"); + serializer.text(masterKeyEncrypted); + serializer.endTag(null, "MasterKey"); + + String salt = Passwords.fetchSalt(); + serializer.startTag(null, "Salt"); + serializer.text(salt); + serializer.endTag(null, "Salt"); + + List crows; + crows = Passwords.getCategoryEntries(); + + int totalPasswords = 0; + + for (CategoryEntry crow : crows) { + + serializer.startTag(null, "Category"); + serializer.attribute(null, "name", crow.name); + + List rows; + rows = Passwords.getPassEntries(crow.id, false, false); + + for (PassEntry row : rows) { + totalPasswords++; + + serializer.startTag(null, "Entry"); + + serializer.startTag(null, "RowID"); + serializer.text(Long.toString(row.id)); + serializer.endTag(null, "RowID"); + + serializer.startTag(null, "Description"); + serializer.text(row.description); + serializer.endTag(null, "Description"); + + serializer.startTag(null, "Website"); + serializer.text(row.website); + serializer.endTag(null, "Website"); + + serializer.startTag(null, "Username"); + serializer.text(row.username); + serializer.endTag(null, "Username"); + + serializer.startTag(null, "Password"); + serializer.text(row.password); + serializer.endTag(null, "Password"); + + serializer.startTag(null, "Note"); + serializer.text(row.note); + serializer.endTag(null, "Note"); + + if (row.uniqueName != null) { + serializer.startTag(null, "UniqueName"); + serializer.text(row.uniqueName); + serializer.endTag(null, "UniqueName"); + } + + ArrayList packageAccess = Passwords.getPackageAccessEntries(row.id); + if (packageAccess != null) { + serializer.startTag(null, "PackageAccess"); + String entry = ""; + Iterator packIter = packageAccess.iterator(); + while (packIter.hasNext()) { + if (entry.length() != 0) { + entry += ","; + } + entry += packIter.next().packageAccess; + } + entry = "[" + entry + "]"; + serializer.text(entry); + serializer.endTag(null, "PackageAccess"); + } + + serializer.endTag(null, "Entry"); + } + serializer.endTag(null, "Category"); + } + + serializer.endTag(null, "OISafe"); + serializer.endDocument(); str.close(); - TimeZone tz = TimeZone.getDefault(); - int julianDay = Time.getJulianDay((new Date()).getTime(), tz.getRawOffset()); - if (debug) Log.d(TAG,"julianDay="+julianDay); - - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(myCtx); - SharedPreferences.Editor editor = sp.edit(); - editor.putInt(Preferences.PREFERENCE_LAST_BACKUP_JULIAN, julianDay); - editor.commit(); - - result=myCtx.getString(R.string.backup_complete)+" "+ - Integer.toString(totalPasswords); - } catch (IOException e) { - e.printStackTrace(); - result=myCtx.getString(R.string.backup_failed)+" "+ - e.getLocalizedMessage(); - return false; - } - return true; - } - public String getResult() { - return result; - } + TimeZone tz = TimeZone.getDefault(); + int julianDay = Time.getJulianDay((new Date()).getTime(), tz.getRawOffset()); + if (debug) { + Log.d(TAG, "julianDay=" + julianDay); + } + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(myCtx); + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(Preferences.PREFERENCE_LAST_BACKUP_JULIAN, julianDay); + editor.commit(); + + result = myCtx.getString(R.string.backup_complete) + " " + + Integer.toString(totalPasswords); + } catch (IOException e) { + e.printStackTrace(); + result = myCtx.getString(R.string.backup_failed) + " " + + e.getLocalizedMessage(); + return false; + } + return true; + } + + public String getResult() { + return result; + } } diff --git a/Safe/src/org/openintents/safe/CSVReader.java b/Safe/src/org/openintents/safe/CSVReader.java index 7113a7ed..978a2eec 100644 --- a/Safe/src/org/openintents/safe/CSVReader.java +++ b/Safe/src/org/openintents/safe/CSVReader.java @@ -1,26 +1,28 @@ -/* $Id$ - */ -package org.openintents.safe; +/* $Id$ + */ +package org.openintents.safe; /** - Copyright 2005 Bytecode Pty Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 + * Copyright 2005 Bytecode Pty Ltd. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

+ * This was found at http://sourceforge.net/projects/opencsv/ + */ - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +/** + * This was found at http://sourceforge.net/projects/opencsv/ */ - -/** - * This was found at http://sourceforge.net/projects/opencsv/ - */ import java.io.BufferedReader; import java.io.IOException; @@ -30,221 +32,222 @@ /** * A very simple CSV reader released under a commercial-friendly license. - * + * * @author Glen Smith - * + * */ public class CSVReader { - private BufferedReader br; - - private boolean hasNext = true; - - private char separator; - - private char quotechar; - - private int skipLines; - - private boolean linesSkiped; - - /** The default separator to use if none is supplied to the constructor. */ - public static final char DEFAULT_SEPARATOR = ','; - - /** - * The default quote character to use if none is supplied to the - * constructor. - */ - public static final char DEFAULT_QUOTE_CHARACTER = '"'; - - /** - * The default line to start reading. - */ - public static final int DEFAULT_SKIP_LINES = 0; - - /** - * Constructs CSVReader using a comma for the separator. - * - * @param reader - * the reader to an underlying CSV source. - */ - public CSVReader(Reader reader) { - this(reader, DEFAULT_SEPARATOR); - } - - /** - * Constructs CSVReader with supplied separator. - * - * @param reader - * the reader to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries. - */ - public CSVReader(Reader reader, char separator) { - this(reader, separator, DEFAULT_QUOTE_CHARACTER); - } - - - /** - * Constructs CSVReader with supplied separator and quote char. - * - * @param reader - * the reader to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries - * @param quotechar - * the character to use for quoted elements - */ - public CSVReader(Reader reader, char separator, char quotechar) { - this(reader, separator, quotechar, DEFAULT_SKIP_LINES); - } - - /** - * Constructs CSVReader with supplied separator and quote char. - * - * @param reader - * the reader to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries - * @param quotechar - * the character to use for quoted elements - * @param line - * the line number to skip for start reading - */ - public CSVReader(Reader reader, char separator, char quotechar, int line) { - this.br = new BufferedReader(reader); - this.separator = separator; - this.quotechar = quotechar; - this.skipLines = line; - } - - /** - * Reads the entire file into a List with each element being a String[] of - * tokens. - * - * @return a List of String[], with each String[] representing a line of the - * file. - * - * @throws IOException - * if bad things happen during the read - */ - public List readAll() throws IOException { - - List allElements = new ArrayList(); - while (hasNext) { - String[] nextLineAsTokens = readNext(); - if (nextLineAsTokens != null) - allElements.add(nextLineAsTokens); - } - return allElements; - - } - - /** - * Reads the next line from the buffer and converts to a string array. - * - * @return a string array with each comma-separated element as a separate - * entry. - * - * @throws IOException - * if bad things happen during the read - */ - public String[] readNext() throws IOException { - - String nextLine = getNextLine(); - return hasNext ? parseLine(nextLine) : null; - } - - /** - * Reads the next line from the file. - * - * @return the next line from the file without trailing newline - * @throws IOException - * if bad things happen during the read - */ - private String getNextLine() throws IOException { - if (!this.linesSkiped) { - for (int i = 0; i < skipLines; i++) { - br.readLine(); - } - this.linesSkiped = true; - } - String nextLine = br.readLine(); - if (nextLine == null) { - hasNext = false; - } - return hasNext ? nextLine : null; - } - - /** - * Parses an incoming String and returns an array of elements. - * - * @param nextLine - * the string to parse - * @return the comma-tokenized list of elements, or null if nextLine is null - * @throws IOException if bad things happen during the read - */ - private String[] parseLine(String nextLine) throws IOException { - - if (nextLine == null) { - return null; - } - - List tokensOnThisLine = new ArrayList(); - StringBuffer sb = new StringBuffer(); - boolean inQuotes = false; - do { - if (inQuotes) { - // continuing a quoted section, reappend newline - sb.append("\n"); - nextLine = getNextLine(); - if (nextLine == null) - break; - } - for (int i = 0; i < nextLine.length(); i++) { - - char c = nextLine.charAt(i); - if (c == quotechar) { - // this gets complex... the quote may end a quoted block, or escape another quote. - // do a 1-char lookahead: - if( inQuotes // we are in quotes, therefore there can be escaped quotes in here. - && nextLine.length() > (i+1) // there is indeed another character to check. - && nextLine.charAt(i+1) == quotechar ){ // ..and that char. is a quote also. - // we have two quote chars in a row == one quote char, so consume them both and - // put one on the token. we do *not* exit the quoted text. - sb.append(nextLine.charAt(i+1)); - i++; - }else{ - inQuotes = !inQuotes; - // the tricky case of an embedded quote in the middle: a,bc"d"ef,g - if(i>2 //not on the begining of the line - && nextLine.charAt(i-1) != this.separator //not at the begining of an escape sequence - && nextLine.length()>(i+1) && - nextLine.charAt(i+1) != this.separator //not at the end of an escape sequence - ){ - sb.append(c); - } - } - } else if (c == separator && !inQuotes) { - tokensOnThisLine.add(sb.toString()); - sb = new StringBuffer(); // start work on next token - } else { - sb.append(c); - } - } - } while (inQuotes); - tokensOnThisLine.add(sb.toString()); - return (String[]) tokensOnThisLine.toArray(new String[0]); - - } - - /** - * Closes the underlying reader. - * - * @throws IOException if the close fails - */ - public void close() throws IOException{ - br.close(); - } + private BufferedReader br; + + private boolean hasNext = true; + + private char separator; + + private char quotechar; + + private int skipLines; + + private boolean linesSkiped; + + /** The default separator to use if none is supplied to the constructor. */ + public static final char DEFAULT_SEPARATOR = ','; + + /** + * The default quote character to use if none is supplied to the + * constructor. + */ + public static final char DEFAULT_QUOTE_CHARACTER = '"'; + + /** + * The default line to start reading. + */ + public static final int DEFAULT_SKIP_LINES = 0; + + /** + * Constructs CSVReader using a comma for the separator. + * + * @param reader + * the reader to an underlying CSV source. + */ + public CSVReader(Reader reader) { + this(reader, DEFAULT_SEPARATOR); + } + + /** + * Constructs CSVReader with supplied separator. + * + * @param reader + * the reader to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries. + */ + public CSVReader(Reader reader, char separator) { + this(reader, separator, DEFAULT_QUOTE_CHARACTER); + } + + /** + * Constructs CSVReader with supplied separator and quote char. + * + * @param reader + * the reader to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + */ + public CSVReader(Reader reader, char separator, char quotechar) { + this(reader, separator, quotechar, DEFAULT_SKIP_LINES); + } + + /** + * Constructs CSVReader with supplied separator and quote char. + * + * @param reader + * the reader to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + * @param line + * the line number to skip for start reading + */ + public CSVReader(Reader reader, char separator, char quotechar, int line) { + this.br = new BufferedReader(reader); + this.separator = separator; + this.quotechar = quotechar; + this.skipLines = line; + } + + /** + * Reads the entire file into a List with each element being a String[] of + * tokens. + * + * @return a List of String[], with each String[] representing a line of the + * file. + * + * @throws IOException + * if bad things happen during the read + */ + public List readAll() throws IOException { + + List allElements = new ArrayList(); + while (hasNext) { + String[] nextLineAsTokens = readNext(); + if (nextLineAsTokens != null) { + allElements.add(nextLineAsTokens); + } + } + return allElements; + + } + + /** + * Reads the next line from the buffer and converts to a string array. + * + * @return a string array with each comma-separated element as a separate + * entry. + * + * @throws IOException + * if bad things happen during the read + */ + public String[] readNext() throws IOException { + + String nextLine = getNextLine(); + return hasNext ? parseLine(nextLine) : null; + } + + /** + * Reads the next line from the file. + * + * @return the next line from the file without trailing newline + * @throws IOException + * if bad things happen during the read + */ + private String getNextLine() throws IOException { + if (!this.linesSkiped) { + for (int i = 0; i < skipLines; i++) { + br.readLine(); + } + this.linesSkiped = true; + } + String nextLine = br.readLine(); + if (nextLine == null) { + hasNext = false; + } + return hasNext ? nextLine : null; + } + + /** + * Parses an incoming String and returns an array of elements. + * + * @param nextLine + * the string to parse + * @return the comma-tokenized list of elements, or null if nextLine is null + * @throws IOException if bad things happen during the read + */ + private String[] parseLine(String nextLine) throws IOException { + + if (nextLine == null) { + return null; + } + + List tokensOnThisLine = new ArrayList(); + StringBuffer sb = new StringBuffer(); + boolean inQuotes = false; + do { + if (inQuotes) { + // continuing a quoted section, reappend newline + sb.append("\n"); + nextLine = getNextLine(); + if (nextLine == null) { + break; + } + } + for (int i = 0; i < nextLine.length(); i++) { + + char c = nextLine.charAt(i); + if (c == quotechar) { + // this gets complex... the quote may end a quoted block, or escape another quote. + // do a 1-char lookahead: + if (inQuotes // we are in quotes, therefore there can be escaped quotes in here. + && nextLine.length() > (i + 1) // there is indeed another character to check. + && nextLine.charAt(i + 1) == quotechar) { // ..and that char. is a quote also. + // we have two quote chars in a row == one quote char, so consume them both and + // put one on the token. we do *not* exit the quoted text. + sb.append(nextLine.charAt(i + 1)); + i++; + } else { + inQuotes = !inQuotes; + // the tricky case of an embedded quote in the middle: a,bc"d"ef,g + if (i > 2 //not on the begining of the line + && nextLine.charAt(i - 1) != this.separator //not at the begining of an escape sequence + && nextLine.length() > (i + 1) && + nextLine.charAt(i + 1) != this.separator //not at the end of an escape sequence + ) { + sb.append(c); + } + } + } else if (c == separator && !inQuotes) { + tokensOnThisLine.add(sb.toString()); + sb = new StringBuffer(); // start work on next token + } else { + sb.append(c); + } + } + } while (inQuotes); + tokensOnThisLine.add(sb.toString()); + return (String[]) tokensOnThisLine.toArray(new String[0]); + + } + + /** + * Closes the underlying reader. + * + * @throws IOException if the close fails + */ + public void close() throws IOException { + br.close(); + } } diff --git a/Safe/src/org/openintents/safe/CSVWriter.java b/Safe/src/org/openintents/safe/CSVWriter.java index 84852218..497eacfe 100644 --- a/Safe/src/org/openintents/safe/CSVWriter.java +++ b/Safe/src/org/openintents/safe/CSVWriter.java @@ -4,19 +4,21 @@ package org.openintents.safe; /** - Copyright 2005 Bytecode Pty Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + * Copyright 2005 Bytecode Pty Ltd. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

+ * This was found at http://opencsv.sourceforge.net/ */ /** @@ -47,364 +49,363 @@ */ public class CSVWriter { - private Writer rawWriter; - - private PrintWriter pw; - - private char separator; - - private char quotechar; - - private char escapechar; - - private String lineEnd; - - /** The character used for escaping quotes. */ - public static final char DEFAULT_ESCAPE_CHARACTER = '"'; - - /** The default separator to use if none is supplied to the constructor. */ - public static final char DEFAULT_SEPARATOR = ','; - - /** - * The default quote character to use if none is supplied to the - * constructor. - */ - public static final char DEFAULT_QUOTE_CHARACTER = '"'; - - /** The quote constant to use when you wish to suppress all quoting. */ - public static final char NO_QUOTE_CHARACTER = '\u0000'; - - /** The escape constant to use when you wish to suppress all escaping. */ - public static final char NO_ESCAPE_CHARACTER = '\u0000'; - - /** Default line terminator uses platform encoding. */ - public static final String DEFAULT_LINE_END = "\n"; - - private static final SimpleDateFormat - TIMESTAMP_FORMATTER = - new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"); - - private static final SimpleDateFormat - DATE_FORMATTER = - new SimpleDateFormat("dd-MMM-yyyy"); - - /** - * Constructs CSVWriter using a comma for the separator. - * - * @param writer - * the writer to an underlying CSV source. - */ - public CSVWriter(Writer writer) { - this(writer, DEFAULT_SEPARATOR); - } - - /** - * Constructs CSVWriter with supplied separator. - * - * @param writer - * the writer to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries. - */ - public CSVWriter(Writer writer, char separator) { - this(writer, separator, DEFAULT_QUOTE_CHARACTER); - } - - /** - * Constructs CSVWriter with supplied separator and quote char. - * - * @param writer - * the writer to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries - * @param quotechar - * the character to use for quoted elements - */ - public CSVWriter(Writer writer, char separator, char quotechar) { - this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER); - } - - /** - * Constructs CSVWriter with supplied separator and quote char. - * - * @param writer - * the writer to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries - * @param quotechar - * the character to use for quoted elements - * @param escapechar - * the character to use for escaping quotechars or escapechars - */ - public CSVWriter(Writer writer, char separator, char quotechar, char escapechar) { - this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END); - } - - /** - * Constructs CSVWriter with supplied separator and quote char. - * - * @param writer - * the writer to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries - * @param quotechar - * the character to use for quoted elements - * @param lineEnd - * the line feed terminator to use - */ - public CSVWriter(Writer writer, char separator, char quotechar, String lineEnd) { - this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd); - } - - /** - * Constructs CSVWriter with supplied separator, quote char, escape char and line ending. - * - * @param writer - * the writer to an underlying CSV source. - * @param separator - * the delimiter to use for separating entries - * @param quotechar - * the character to use for quoted elements - * @param escapechar - * the character to use for escaping quotechars or escapechars - * @param lineEnd - * the line feed terminator to use - */ - public CSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) { - this.rawWriter = writer; - this.pw = new PrintWriter(writer); - this.separator = separator; - this.quotechar = quotechar; - this.escapechar = escapechar; - this.lineEnd = lineEnd; - } - - /** - * Writes the entire list to a CSV file. The list is assumed to be a - * String[] - * - * @param allLines - * a List of String[], with each String[] representing a line of - * the file. - */ - public void writeAll(List allLines) { - - for (Iterator iter = allLines.iterator(); iter.hasNext();) { - String[] nextLine = (String[]) iter.next(); - writeNext(nextLine); - } - - } - - protected void writeColumnNames(ResultSetMetaData metadata) - throws SQLException { - - int columnCount = metadata.getColumnCount(); - - String[] nextLine = new String[columnCount]; - for (int i = 0; i < columnCount; i++) { - nextLine[i] = metadata.getColumnName(i + 1); - } - writeNext(nextLine); - } - - /** - * Writes the entire ResultSet to a CSV file. - * - * The caller is responsible for closing the ResultSet. - * - * @param rs the recordset to write - * @param includeColumnNames true if you want column names in the output, false otherwise - * - */ - public void writeAll(java.sql.ResultSet rs, boolean includeColumnNames) throws SQLException, IOException { - - ResultSetMetaData metadata = rs.getMetaData(); - - - if (includeColumnNames) { - writeColumnNames(metadata); - } - - int columnCount = metadata.getColumnCount(); - - while (rs.next()) - { - String[] nextLine = new String[columnCount]; - - for (int i = 0; i < columnCount; i++) { - nextLine[i] = getColumnValue(rs, metadata.getColumnType(i + 1), i + 1); - } - - writeNext(nextLine); - } - } - - private static String getColumnValue(ResultSet rs, int colType, int colIndex) - throws SQLException, IOException { - - String value = ""; - - switch (colType) - { - case Types.BIT: - Object bit = rs.getObject(colIndex); - if (bit != null) { - value = String.valueOf(bit); - } - break; - case Types.BOOLEAN: - boolean b = rs.getBoolean(colIndex); - if (!rs.wasNull()) { - value = Boolean.valueOf(b).toString(); - } - break; - case Types.CLOB: - Clob c = rs.getClob(colIndex); - if (c != null) { - value = read(c); - } - break; - case Types.BIGINT: - case Types.DECIMAL: - case Types.DOUBLE: - case Types.FLOAT: - case Types.REAL: - case Types.NUMERIC: - BigDecimal bd = rs.getBigDecimal(colIndex); - if (bd != null) { - value = "" + bd.doubleValue(); - } - break; - case Types.INTEGER: - case Types.TINYINT: - case Types.SMALLINT: - int intValue = rs.getInt(colIndex); - if (!rs.wasNull()) { - value = "" + intValue; - } - break; - case Types.JAVA_OBJECT: - Object obj = rs.getObject(colIndex); - if (obj != null) { - value = String.valueOf(obj); - } - break; - case Types.DATE: - java.sql.Date date = rs.getDate(colIndex); - if (date != null) { - value = DATE_FORMATTER.format(date);; - } - break; - case Types.TIME: - Time t = rs.getTime(colIndex); - if (t != null) { - value = t.toString(); - } - break; - case Types.TIMESTAMP: - Timestamp tstamp = rs.getTimestamp(colIndex); - if (tstamp != null) { - value = TIMESTAMP_FORMATTER.format(tstamp); - } - break; - case Types.LONGVARCHAR: - case Types.VARCHAR: - case Types.CHAR: - value = rs.getString(colIndex); - break; - default: - value = ""; - } - - - if (value == null) - { - value = ""; - } - - return value; - - } - - private static String read(Clob c) throws SQLException, IOException - { - StringBuffer sb = new StringBuffer( (int) c.length()); - Reader r = c.getCharacterStream(); - char[] cbuf = new char[2048]; - int n = 0; - while ((n = r.read(cbuf, 0, cbuf.length)) != -1) { - if (n > 0) { - sb.append(cbuf, 0, n); - } - } - return sb.toString(); - } - - /** - * Writes the next line to the file. - * - * @param nextLine - * a string array with each comma-separated element as a separate - * entry. - */ - public void writeNext(String[] nextLine) { - - if (nextLine == null) - return; - - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < nextLine.length; i++) { - - if (i != 0) { - sb.append(separator); - } - - String nextElement = nextLine[i]; - if (nextElement == null) - continue; - if (quotechar != NO_QUOTE_CHARACTER) - sb.append(quotechar); - for (int j = 0; j < nextElement.length(); j++) { - char nextChar = nextElement.charAt(j); - if (escapechar != NO_ESCAPE_CHARACTER && nextChar == quotechar) { - sb.append(escapechar).append(nextChar); - } else if (escapechar != NO_ESCAPE_CHARACTER && nextChar == escapechar) { - sb.append(escapechar).append(nextChar); - } else { - sb.append(nextChar); - } - } - if (quotechar != NO_QUOTE_CHARACTER) - sb.append(quotechar); - } - - sb.append(lineEnd); - pw.write(sb.toString()); - - } - - /** - * Flush underlying stream to writer. - * - * @throws IOException if bad things happen - */ - public void flush() throws IOException { - - pw.flush(); - - } - - /** - * Close the underlying stream writer flushing any buffered content. - * - * @throws IOException if bad things happen - * - */ - public void close() throws IOException { - pw.flush(); - pw.close(); - rawWriter.close(); - } + private Writer rawWriter; + + private PrintWriter pw; + + private char separator; + + private char quotechar; + + private char escapechar; + + private String lineEnd; + + /** The character used for escaping quotes. */ + public static final char DEFAULT_ESCAPE_CHARACTER = '"'; + + /** The default separator to use if none is supplied to the constructor. */ + public static final char DEFAULT_SEPARATOR = ','; + + /** + * The default quote character to use if none is supplied to the + * constructor. + */ + public static final char DEFAULT_QUOTE_CHARACTER = '"'; + + /** The quote constant to use when you wish to suppress all quoting. */ + public static final char NO_QUOTE_CHARACTER = '\u0000'; + + /** The escape constant to use when you wish to suppress all escaping. */ + public static final char NO_ESCAPE_CHARACTER = '\u0000'; + + /** Default line terminator uses platform encoding. */ + public static final String DEFAULT_LINE_END = "\n"; + + private static final SimpleDateFormat + TIMESTAMP_FORMATTER = + new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"); + + private static final SimpleDateFormat + DATE_FORMATTER = + new SimpleDateFormat("dd-MMM-yyyy"); + + /** + * Constructs CSVWriter using a comma for the separator. + * + * @param writer + * the writer to an underlying CSV source. + */ + public CSVWriter(Writer writer) { + this(writer, DEFAULT_SEPARATOR); + } + + /** + * Constructs CSVWriter with supplied separator. + * + * @param writer + * the writer to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries. + */ + public CSVWriter(Writer writer, char separator) { + this(writer, separator, DEFAULT_QUOTE_CHARACTER); + } + + /** + * Constructs CSVWriter with supplied separator and quote char. + * + * @param writer + * the writer to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + */ + public CSVWriter(Writer writer, char separator, char quotechar) { + this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER); + } + + /** + * Constructs CSVWriter with supplied separator and quote char. + * + * @param writer + * the writer to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + * @param escapechar + * the character to use for escaping quotechars or escapechars + */ + public CSVWriter(Writer writer, char separator, char quotechar, char escapechar) { + this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END); + } + + /** + * Constructs CSVWriter with supplied separator and quote char. + * + * @param writer + * the writer to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + * @param lineEnd + * the line feed terminator to use + */ + public CSVWriter(Writer writer, char separator, char quotechar, String lineEnd) { + this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd); + } + + /** + * Constructs CSVWriter with supplied separator, quote char, escape char and line ending. + * + * @param writer + * the writer to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + * @param escapechar + * the character to use for escaping quotechars or escapechars + * @param lineEnd + * the line feed terminator to use + */ + public CSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) { + this.rawWriter = writer; + this.pw = new PrintWriter(writer); + this.separator = separator; + this.quotechar = quotechar; + this.escapechar = escapechar; + this.lineEnd = lineEnd; + } + + /** + * Writes the entire list to a CSV file. The list is assumed to be a + * String[] + * + * @param allLines + * a List of String[], with each String[] representing a line of + * the file. + */ + public void writeAll(List allLines) { + + for (Iterator iter = allLines.iterator(); iter.hasNext(); ) { + String[] nextLine = (String[]) iter.next(); + writeNext(nextLine); + } + + } + + protected void writeColumnNames(ResultSetMetaData metadata) + throws SQLException { + + int columnCount = metadata.getColumnCount(); + + String[] nextLine = new String[columnCount]; + for (int i = 0; i < columnCount; i++) { + nextLine[i] = metadata.getColumnName(i + 1); + } + writeNext(nextLine); + } + + /** + * Writes the entire ResultSet to a CSV file. + * + * The caller is responsible for closing the ResultSet. + * + * @param rs the recordset to write + * @param includeColumnNames true if you want column names in the output, false otherwise + * + */ + public void writeAll(java.sql.ResultSet rs, boolean includeColumnNames) throws SQLException, IOException { + + ResultSetMetaData metadata = rs.getMetaData(); + + if (includeColumnNames) { + writeColumnNames(metadata); + } + + int columnCount = metadata.getColumnCount(); + + while (rs.next()) { + String[] nextLine = new String[columnCount]; + + for (int i = 0; i < columnCount; i++) { + nextLine[i] = getColumnValue(rs, metadata.getColumnType(i + 1), i + 1); + } + + writeNext(nextLine); + } + } + + private static String getColumnValue(ResultSet rs, int colType, int colIndex) + throws SQLException, IOException { + + String value = ""; + + switch (colType) { + case Types.BIT: + Object bit = rs.getObject(colIndex); + if (bit != null) { + value = String.valueOf(bit); + } + break; + case Types.BOOLEAN: + boolean b = rs.getBoolean(colIndex); + if (!rs.wasNull()) { + value = Boolean.valueOf(b).toString(); + } + break; + case Types.CLOB: + Clob c = rs.getClob(colIndex); + if (c != null) { + value = read(c); + } + break; + case Types.BIGINT: + case Types.DECIMAL: + case Types.DOUBLE: + case Types.FLOAT: + case Types.REAL: + case Types.NUMERIC: + BigDecimal bd = rs.getBigDecimal(colIndex); + if (bd != null) { + value = "" + bd.doubleValue(); + } + break; + case Types.INTEGER: + case Types.TINYINT: + case Types.SMALLINT: + int intValue = rs.getInt(colIndex); + if (!rs.wasNull()) { + value = "" + intValue; + } + break; + case Types.JAVA_OBJECT: + Object obj = rs.getObject(colIndex); + if (obj != null) { + value = String.valueOf(obj); + } + break; + case Types.DATE: + java.sql.Date date = rs.getDate(colIndex); + if (date != null) { + value = DATE_FORMATTER.format(date); + ; + } + break; + case Types.TIME: + Time t = rs.getTime(colIndex); + if (t != null) { + value = t.toString(); + } + break; + case Types.TIMESTAMP: + Timestamp tstamp = rs.getTimestamp(colIndex); + if (tstamp != null) { + value = TIMESTAMP_FORMATTER.format(tstamp); + } + break; + case Types.LONGVARCHAR: + case Types.VARCHAR: + case Types.CHAR: + value = rs.getString(colIndex); + break; + default: + value = ""; + } + + if (value == null) { + value = ""; + } + + return value; + + } + + private static String read(Clob c) throws SQLException, IOException { + StringBuffer sb = new StringBuffer((int) c.length()); + Reader r = c.getCharacterStream(); + char[] cbuf = new char[2048]; + int n = 0; + while ((n = r.read(cbuf, 0, cbuf.length)) != -1) { + if (n > 0) { + sb.append(cbuf, 0, n); + } + } + return sb.toString(); + } + + /** + * Writes the next line to the file. + * + * @param nextLine + * a string array with each comma-separated element as a separate + * entry. + */ + public void writeNext(String[] nextLine) { + + if (nextLine == null) { + return; + } + + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < nextLine.length; i++) { + + if (i != 0) { + sb.append(separator); + } + + String nextElement = nextLine[i]; + if (nextElement == null) { + continue; + } + if (quotechar != NO_QUOTE_CHARACTER) { + sb.append(quotechar); + } + for (int j = 0; j < nextElement.length(); j++) { + char nextChar = nextElement.charAt(j); + if (escapechar != NO_ESCAPE_CHARACTER && nextChar == quotechar) { + sb.append(escapechar).append(nextChar); + } else if (escapechar != NO_ESCAPE_CHARACTER && nextChar == escapechar) { + sb.append(escapechar).append(nextChar); + } else { + sb.append(nextChar); + } + } + if (quotechar != NO_QUOTE_CHARACTER) { + sb.append(quotechar); + } + } + + sb.append(lineEnd); + pw.write(sb.toString()); + + } + + /** + * Flush underlying stream to writer. + * + * @throws IOException if bad things happen + */ + public void flush() throws IOException { + + pw.flush(); + + } + + /** + * Close the underlying stream writer flushing any buffered content. + * + * @throws IOException if bad things happen + * + */ + public void close() throws IOException { + pw.flush(); + pw.close(); + rawWriter.close(); + } } diff --git a/Safe/src/org/openintents/safe/CategoryEdit.java b/Safe/src/org/openintents/safe/CategoryEdit.java index bff326fc..46184a1e 100644 --- a/Safe/src/org/openintents/safe/CategoryEdit.java +++ b/Safe/src/org/openintents/safe/CategoryEdit.java @@ -16,8 +16,6 @@ */ package org.openintents.safe; -import org.openintents.intents.CryptoIntents; - import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; @@ -30,165 +28,193 @@ import android.widget.EditText; import android.widget.Toast; +import org.openintents.intents.CryptoIntents; + /** * CategoryEdit Activity - * + * * @author Randy McEoin */ public class CategoryEdit extends Activity { - private static final boolean debug = false; - private static String TAG = "CategoryEdit"; - - private EditText nameText; - private Long RowId; - boolean populated = false; - - Intent frontdoor; - private Intent restartTimerIntent=null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - if (debug) Log.d(TAG,"onCreate("+icicle+")"); - - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent (CryptoIntents.ACTION_RESTART_TIMER); - - String title = getResources().getString(R.string.app_name) + " - " + - getResources().getString(R.string.edit_entry); - setTitle(title); - - setContentView(R.layout.cat_edit); - - nameText = (EditText) findViewById(R.id.name); - - Button confirmButton = (Button) findViewById(R.id.save_category); - - RowId = icicle != null ? icicle.getLong(CategoryList.KEY_ID) : null; - if (RowId == null) { - Bundle extras = getIntent().getExtras(); - RowId = extras != null ? extras.getLong(CategoryList.KEY_ID) : null; - } - - confirmButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - // Don't allow the user to enter a blank name, we need - // something useful to show in the list - if(nameText.getText().toString().trim().length() == 0) { - Toast.makeText(CategoryEdit.this, R.string.notify_blank_name, - Toast.LENGTH_SHORT).show(); - return; - } - saveState(); - setResult(RESULT_OK); - finish(); - } - }); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (RowId != null) { - outState.putLong(CategoryList.KEY_ID, RowId); - } else { - outState.putLong(CategoryList.KEY_ID, -1); - } - } - - @Override - protected void onRestoreInstanceState(Bundle inState) { - super.onRestoreInstanceState(inState); - - if (debug) Log.d(TAG,"onRestoreInstanceState("+inState+")"); - // because the various EditText automatically handle state - // when we come back there is no need to re-populate - populated=true; - } - - @Override - protected void onPause() { - super.onPause(); - if (debug) Log.d(TAG, "onPause"); - - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - protected void onResume() { - super.onResume(); - if (debug) Log.d(TAG, "onResume"); - if (!CategoryList.isSignedIn()) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - - Passwords.Initialize(this); - - populateFields(); - } - - private void saveState() { - if (debug) Log.d(TAG, "saveState"); - CategoryEntry entry = new CategoryEntry(); - - String namePlain = nameText.getText().toString(); - if (debug) Log.d(TAG, "name: " + namePlain); - entry.plainName=namePlain; - - if(RowId == null || RowId == -1) { - entry.id=-1; - } else { - entry.id=RowId; - } - if (debug) Log.d(TAG, "addCategory"); - RowId=Passwords.putCategoryEntry(entry); - } - - /** - * - */ - private void populateFields() { - if (debug) Log.d(TAG, "populateFields"); - if (populated) { - return; - } - if ((RowId != null) && (RowId > 0)) { - CategoryEntry catEntry = Passwords.getCategoryEntry(RowId); - if (catEntry==null) { - return; - } - nameText.setText(catEntry.plainName); - } - populated=true; - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (debug) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + private static final boolean debug = false; + private static String TAG = "CategoryEdit"; + + private EditText nameText; + private Long RowId; + boolean populated = false; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; + + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + if (debug) { + Log.d(TAG, "onCreate(" + icicle + ")"); + } + + frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.edit_entry); + setTitle(title); + + setContentView(R.layout.cat_edit); + + nameText = (EditText) findViewById(R.id.name); + + Button confirmButton = (Button) findViewById(R.id.save_category); + + RowId = icicle != null ? icicle.getLong(CategoryList.KEY_ID) : null; + if (RowId == null) { + Bundle extras = getIntent().getExtras(); + RowId = extras != null ? extras.getLong(CategoryList.KEY_ID) : null; + } + + confirmButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + // Don't allow the user to enter a blank name, we need + // something useful to show in the list + if (nameText.getText().toString().trim().length() == 0) { + Toast.makeText( + CategoryEdit.this, R.string.notify_blank_name, + Toast.LENGTH_SHORT + ).show(); + return; + } + saveState(); + setResult(RESULT_OK); + finish(); + } + } + ); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (RowId != null) { + outState.putLong(CategoryList.KEY_ID, RowId); + } else { + outState.putLong(CategoryList.KEY_ID, -1); + } + } + + @Override + protected void onRestoreInstanceState(Bundle inState) { + super.onRestoreInstanceState(inState); + + if (debug) { + Log.d(TAG, "onRestoreInstanceState(" + inState + ")"); + } + // because the various EditText automatically handle state + // when we come back there is no need to re-populate + populated = true; + } + + @Override + protected void onPause() { + super.onPause(); + if (debug) { + Log.d(TAG, "onPause"); + } + + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (debug) { + Log.d(TAG, "onResume"); + } + if (!CategoryList.isSignedIn()) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + + Passwords.Initialize(this); + + populateFields(); + } + + private void saveState() { + if (debug) { + Log.d(TAG, "saveState"); + } + CategoryEntry entry = new CategoryEntry(); + + String namePlain = nameText.getText().toString(); + if (debug) { + Log.d(TAG, "name: " + namePlain); + } + entry.plainName = namePlain; + + if (RowId == null || RowId == -1) { + entry.id = -1; + } else { + entry.id = RowId; + } + if (debug) { + Log.d(TAG, "addCategory"); + } + RowId = Passwords.putCategoryEntry(entry); + } + + /** + * + */ + private void populateFields() { + if (debug) { + Log.d(TAG, "populateFields"); + } + if (populated) { + return; + } + if ((RowId != null) && (RowId > 0)) { + CategoryEntry catEntry = Passwords.getCategoryEntry(RowId); + if (catEntry == null) { + return; + } + nameText.setText(catEntry.plainName); + } + populated = true; + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // startActivity(frontdoor); - }else{ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } } diff --git a/Safe/src/org/openintents/safe/CategoryEntry.java b/Safe/src/org/openintents/safe/CategoryEntry.java index 659cfaf5..6aea4fd5 100644 --- a/Safe/src/org/openintents/safe/CategoryEntry.java +++ b/Safe/src/org/openintents/safe/CategoryEntry.java @@ -20,37 +20,37 @@ * @author Randy McEoin */ public class CategoryEntry extends Object { - public long id=-1; - public String name; - public boolean nameNeedsDecrypt; - public String plainName; - public boolean plainNameNeedsEncrypt=true; - int count=0; - - public String getName() { - return name; - } - - public int getCount() { - return count; - } - - public CategoryEntry () { - name = ""; - } - - public CategoryEntry (String _name) { - name = _name; - } - - public CategoryEntry (String _name, int _count) { - name = _name; - count = _count; - } - - @Override - public String toString() { - return name + " " + count; - } + public long id = -1; + public String name; + public boolean nameNeedsDecrypt; + public String plainName; + public boolean plainNameNeedsEncrypt = true; + int count = 0; + + public String getName() { + return name; + } + + public int getCount() { + return count; + } + + public CategoryEntry() { + name = ""; + } + + public CategoryEntry(String _name) { + name = _name; + } + + public CategoryEntry(String _name, int _count) { + name = _name; + count = _count; + } + + @Override + public String toString() { + return name + " " + count; + } } diff --git a/Safe/src/org/openintents/safe/CategoryList.java b/Safe/src/org/openintents/safe/CategoryList.java index 85cbf63f..4d8813d8 100644 --- a/Safe/src/org/openintents/safe/CategoryList.java +++ b/Safe/src/org/openintents/safe/CategoryList.java @@ -15,31 +15,6 @@ */ package org.openintents.safe; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.TimeZone; - -import org.openintents.distribution.AboutDialog; -import org.openintents.intents.AboutMiniIntents; -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.dialog.DialogHostingActivity; -import org.openintents.safe.password.Master; -import org.openintents.safe.service.AutoLockService; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.honeycomb.WrapActionBar; -import org.openintents.safe.wrappers.honeycomb.ClipboardManager; -import org.openintents.util.IntentUtils; -import org.openintents.util.SecureDelete; - import android.app.AlertDialog; import android.app.Dialog; import android.app.ListActivity; @@ -47,7 +22,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; - import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -62,619 +36,698 @@ import android.text.format.Time; import android.util.Log; import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ContextMenu.ContextMenuInfo; import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.CheckBox; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.Toast; -import android.widget.AdapterView.AdapterContextMenuInfo; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TimeZone; + +import org.openintents.distribution.AboutDialog; +import org.openintents.intents.AboutMiniIntents; +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.dialog.DialogHostingActivity; +import org.openintents.safe.password.Master; +import org.openintents.safe.service.AutoLockService; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.honeycomb.ClipboardManager; +import org.openintents.safe.wrappers.honeycomb.WrapActionBar; +import org.openintents.util.IntentUtils; +import org.openintents.util.SecureDelete; /** * CategoryList Activity - * + * * @author Randy McEoin * @author Steven Osborn - http://steven.bitsetters.com */ public class CategoryList extends ListActivity { - private static boolean debug = false; - private static final String TAG = "CategoryList"; - - // Menu Item order - public static final int LOCK_CATEGORY_INDEX = Menu.FIRST; - public static final int OPEN_CATEGORY_INDEX = Menu.FIRST + 1; - public static final int EDIT_CATEGORY_INDEX = Menu.FIRST + 2; - public static final int ADD_CATEGORY_INDEX = Menu.FIRST + 3; - public static final int DEL_CATEGORY_INDEX = Menu.FIRST + 4; - public static final int HELP_INDEX = Menu.FIRST + 5; - public static final int SEARCH_INDEX = Menu.FIRST + 6; - public static final int EXPORT_INDEX = Menu.FIRST + 7; - public static final int IMPORT_INDEX = Menu.FIRST + 8; - public static final int CHANGE_PASS_INDEX = Menu.FIRST + 9; - public static final int BACKUP_INDEX = Menu.FIRST + 10; - public static final int RESTORE_INDEX = Menu.FIRST + 11; - public static final int PREFERENCES_INDEX = Menu.FIRST + 12; - public static final int ABOUT_INDEX = Menu.FIRST + 13; - - public static final int REQUEST_ONCREATE = 0; - public static final int REQUEST_EDIT_CATEGORY = 1; - public static final int REQUEST_ADD_CATEGORY = 2; - public static final int REQUEST_OPEN_CATEGORY = 3; - public static final int REQUEST_RESTORE = 4; - public static final int REQUEST_IMPORT_FILENAME = 5; - public static final int REQUEST_EXPORT_FILENAME = 6; - public static final int REQUEST_BACKUP_FILENAME = 7; + private static boolean debug = false; + private static final String TAG = "CategoryList"; + + // Menu Item order + public static final int LOCK_CATEGORY_INDEX = Menu.FIRST; + public static final int OPEN_CATEGORY_INDEX = Menu.FIRST + 1; + public static final int EDIT_CATEGORY_INDEX = Menu.FIRST + 2; + public static final int ADD_CATEGORY_INDEX = Menu.FIRST + 3; + public static final int DEL_CATEGORY_INDEX = Menu.FIRST + 4; + public static final int HELP_INDEX = Menu.FIRST + 5; + public static final int SEARCH_INDEX = Menu.FIRST + 6; + public static final int EXPORT_INDEX = Menu.FIRST + 7; + public static final int IMPORT_INDEX = Menu.FIRST + 8; + public static final int CHANGE_PASS_INDEX = Menu.FIRST + 9; + public static final int BACKUP_INDEX = Menu.FIRST + 10; + public static final int RESTORE_INDEX = Menu.FIRST + 11; + public static final int PREFERENCES_INDEX = Menu.FIRST + 12; + public static final int ABOUT_INDEX = Menu.FIRST + 13; + + public static final int REQUEST_ONCREATE = 0; + public static final int REQUEST_EDIT_CATEGORY = 1; + public static final int REQUEST_ADD_CATEGORY = 2; + public static final int REQUEST_OPEN_CATEGORY = 3; + public static final int REQUEST_RESTORE = 4; + public static final int REQUEST_IMPORT_FILENAME = 5; + public static final int REQUEST_EXPORT_FILENAME = 6; + public static final int REQUEST_BACKUP_FILENAME = 7; public static final int REQUEST_BACKUP_DOCUMENT = 8; - private static final int ABOUT_KEY = 2; - - public static final int MAX_CATEGORIES = 256; - - private static final String PASSWORDSAFE_IMPORT_FILENAME = "passwordsafe.csv"; - - public static final String KEY_ID = "id"; // Intent keys - - private static importTask taskImport = null; - private ProgressDialog importProgress = null; - private static boolean importDeletedDatabase = false; - - private static backupTask taskBackup = null; - private ProgressDialog backupProgress = null; - - private List rows=null; - private CategoryListItemAdapter catAdapter=null; - private Intent restartTimerIntent=null; - private int lastPosition=0; - - private AlertDialog autobackupDialog; - - private boolean lockOnScreenLock=true; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { - if (debug) Log.d(TAG,"caught ACTION_SCREEN_OFF"); - if (lockOnScreenLock) { - Master.setMasterKey(null); - } - } else if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - lockAndShutFrontDoor(); - } - } - }; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - if (debug) Log.d(TAG,"onCreate("+icicle+")"); - - restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); - - Passwords.Initialize(this); + private static final int ABOUT_KEY = 2; - setContentView(R.layout.cat_list); - String title = getResources().getString(R.string.app_name) + " - " + - getResources().getString(R.string.categories); - setTitle(title); + public static final int MAX_CATEGORIES = 256; - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction (CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); + private static final String PASSWORDSAFE_IMPORT_FILENAME = "passwordsafe.csv"; - - final ListView list = getListView(); - list.setFocusable(true); - list.setOnCreateContextMenuListener(this); - list.setTextFilterEnabled(true); - registerForContextMenu(list); - } - - @Override - protected void onResume() { - super.onResume(); - - if (debug) Log.d(TAG,"onResume()"); - - if (isSignedIn()==false) { - Intent frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - - showFirstTimeWarningDialog(); - if (Passwords.getPrePopulate()==true) - { - prePopulate(); - Passwords.clearPrePopulate(); - } - - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - lockOnScreenLock = sp.getBoolean(Preferences.PREFERENCE_LOCK_ON_SCREEN_LOCK, true); - - if (taskImport!=null) { - // taskImport still running - taskImport.setActivity(this); - startImportProgressDialog(); - return; - } - Passwords.Initialize(this); - - ListAdapter la=getListAdapter(); - if (la!=null) { - if (debug) Log.d(TAG,"onResume: count="+la.getCount()); - } else { - if (debug) Log.d(TAG,"onResume: no list"); - fillData(); - } - checkForAutoBackup(); - } - - private void checkForAutoBackup() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - boolean prefAutobackup = sp.getBoolean(Preferences.PREFERENCE_AUTOBACKUP, true); - - if (prefAutobackup==false) { - return; - } - if (Passwords.countPasswords(-1)<1) { - // if no passwords populated yet, then nevermind - return; - } - TimeZone tz = TimeZone.getDefault(); - int julianDay = Time.getJulianDay((new Date()).getTime(), tz.getRawOffset()); - - SharedPreferences.Editor editor = sp.edit(); - - int lastAutobackupCheck = sp.getInt(Preferences.PREFERENCE_LAST_AUTOBACKUP_CHECK, 0); - editor.putInt(Preferences.PREFERENCE_LAST_AUTOBACKUP_CHECK, julianDay); - editor.commit(); - if (lastAutobackupCheck==0) { - // first time - if (debug) Log.d(TAG,"first time autobackup"); - return; - } - int lastBackupJulian = sp.getInt(Preferences.PREFERENCE_LAST_BACKUP_JULIAN, 0); - String maxDaysToAutobackupString=sp.getString(Preferences.PREFERENCE_AUTOBACKUP_DAYS, - Preferences.PREFERENCE_AUTOBACKUP_DAYS_DEFAULT_VALUE); - int maxDaysToAutobackup=7; - try { - maxDaysToAutobackup = Integer.valueOf(maxDaysToAutobackupString); - } catch (NumberFormatException e) { - Log.d(TAG,"why is autobackup_days busted?"); - } - - int daysSinceLastBackup=julianDay-lastBackupJulian; - if (((julianDay-lastAutobackupCheck)>(maxDaysToAutobackup-1)) && - ((daysSinceLastBackup)>(maxDaysToAutobackup-1))) { - if (debug) Log.d(TAG,"in need of backup"); - // used a custom layout in order to get the checkbox - AlertDialog.Builder builder; - - LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE); - View layout = inflater.inflate(R.layout.auto_backup,null); - - builder = new AlertDialog.Builder(this); - builder.setView(layout); - builder.setTitle(getString(R.string.autobackup)); - builder.setIcon(android.R.drawable.ic_menu_save); - builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - checkAutobackupTurnoff(); - } - }); - builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - checkAutobackupTurnoff(); - backupThreadStart(); - } - }); - if (daysSinceLastBackup==julianDay) { - builder.setMessage(R.string.backup_never); - } else { - String backupInDays = String.format(getString(R.string.backup_in_days), daysSinceLastBackup); - builder.setMessage(backupInDays); - } - autobackupDialog = builder.create(); - autobackupDialog.show(); - } - } - private void checkAutobackupTurnoff() { - CheckBox autobackupTurnoff=(CheckBox) autobackupDialog.findViewById(R.id.autobackup_turnoff); - if (autobackupTurnoff.isChecked()) { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(Preferences.PREFERENCE_AUTOBACKUP, false); - editor.commit(); - } - } - /** - * - */ - private void showFirstTimeWarningDialog() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - boolean firstTimeWarning = sp.getBoolean(Preferences.PREFERENCE_FIRST_TIME_WARNING, false); - - if (!firstTimeWarning) { - Intent i = new Intent(this, DialogHostingActivity.class); - i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_FIRST_TIME_WARNING); - startActivity(i); - - SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(Preferences.PREFERENCE_FIRST_TIME_WARNING, true); - editor.commit(); - } - } - - @Override - protected void onPause() { - super.onPause(); - - if (debug) Log.d(TAG,"onPause()"); - - if (taskImport != null) { - importProgress.dismiss(); - taskImport.setActivity(null); - } - if (taskBackup != null) { - backupProgress.dismiss(); - taskBackup.setActivity(null); - } - - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - public void onStop() { - super.onStop(); - - if (debug) Log.d(TAG,"onStop()"); - } - - @Override - public void onDestroy() { - super.onDestroy(); - - if (debug) Log.d(TAG,"onDestroy()"); - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - @Override - public void onCreateContextMenu(ContextMenu menu, View view, - ContextMenuInfo menuInfo) { - - AdapterView.AdapterContextMenuInfo info; - info = (AdapterView.AdapterContextMenuInfo) menuInfo; - - menu.setHeaderTitle(rows.get(info.position).plainName); - menu.add(0,OPEN_CATEGORY_INDEX, 0, R.string.open) - .setIcon(android.R.drawable.ic_menu_view) - .setAlphabeticShortcut('o'); - menu.add(0,EDIT_CATEGORY_INDEX, 0, R.string.password_edit) - .setIcon(android.R.drawable.ic_menu_edit) - .setAlphabeticShortcut('e'); - menu.add(0, DEL_CATEGORY_INDEX, 0, R.string.password_delete) - .setIcon(android.R.drawable.ic_menu_delete) - .setAlphabeticShortcut('d'); - } - @Override - public boolean onContextItemSelected(MenuItem item) { - onOptionsItemSelected(item); - return true; - } - - @Override - protected Dialog onCreateDialog(int id) { - switch (id) { - case ABOUT_KEY: - return new AboutDialog(this); - } - return null; - } - - /** - * Returns the current status of signedIn. - * - * @return True if signed in - */ - public static boolean isSignedIn() { - if ((Master.getSalt() != null) && (Master.getMasterKey() != null)) { - if (debug) Log.d(TAG,"isSignedIn: true"); - return true; - } - if (debug) Log.d(TAG,"isSignedIn: false"); - return false; - } - - /** - * Sets signedIn status to false. - * - * @see org.openintents.safe.CategoryList#isSignedIn - */ - public static void setSignedOut() { - if (debug) Log.d(TAG,"setSignedOut()"); - Master.setMasterKey(null); - } - /** - * Populates the category ListView - */ - private void fillData() { - if (debug) Log.d(TAG,"fillData()"); - - rows=Passwords.getCategoryEntries(); - if (debug) Log.d(TAG,"fillData: rows="+rows.size()); - - catAdapter = - new CategoryListItemAdapter(this, R.layout.cat_row, - rows); - setListAdapter(catAdapter); - - } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - if (menu == null) { - return super.onMenuOpened(featureId, menu); - } - MenuItem miDelete = menu.findItem(DEL_CATEGORY_INDEX); - MenuItem miEdit = menu.findItem(EDIT_CATEGORY_INDEX); - if (getSelectedItemPosition() > -1) { - miDelete.setEnabled(true); - miEdit.setEnabled(true); - } else { - miDelete.setEnabled(false); - miEdit.setEnabled(false); - } - return super.onMenuOpened(featureId, menu); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem item = menu.add(0,LOCK_CATEGORY_INDEX, 0, R.string.password_lock) - .setIcon(android.R.drawable.ic_lock_lock) - .setShortcut('0', 'l'); - if (CheckWrappers.mActionBarAvailable) { - WrapActionBar.showIfRoom(item); - } - - menu.add(0,EDIT_CATEGORY_INDEX, 0, R.string.password_edit) - .setIcon(android.R.drawable.ic_menu_edit) - .setShortcut('1', 'e'); - - menu.add(0,ADD_CATEGORY_INDEX, 0, R.string.password_add) - .setIcon(android.R.drawable.ic_menu_add) - .setShortcut('2', 'a'); - - item = menu.add(0, SEARCH_INDEX, 0, R.string.search) - .setIcon(android.R.drawable.ic_menu_search); - if (CheckWrappers.mActionBarAvailable) { - WrapActionBar.showIfRoom(item); - } - - menu.add(0, DEL_CATEGORY_INDEX, 0, R.string.password_delete) - .setIcon(android.R.drawable.ic_menu_delete) - .setEnabled(false); - - menu.add(0, HELP_INDEX, 0, R.string.help) - .setIcon(android.R.drawable.ic_menu_help); + public static final String KEY_ID = "id"; // Intent keys - menu.add(0, EXPORT_INDEX, 0, R.string.export_database) - .setIcon(android.R.drawable.ic_menu_upload); - menu.add(0, IMPORT_INDEX, 0, R.string.import_database) - .setIcon(android.R.drawable.ic_input_get); + private static importTask taskImport = null; + private ProgressDialog importProgress = null; + private static boolean importDeletedDatabase = false; - menu.add(0, CHANGE_PASS_INDEX, 0, R.string.change_password) - .setIcon(android.R.drawable.ic_menu_manage); + private static backupTask taskBackup = null; + private ProgressDialog backupProgress = null; - menu.add(0, BACKUP_INDEX, 0, R.string.backup); - menu.add(0, RESTORE_INDEX, 0, R.string.restore); + private List rows = null; + private CategoryListItemAdapter catAdapter = null; + private Intent restartTimerIntent = null; + private int lastPosition = 0; - menu.add(0, PREFERENCES_INDEX, 0, R.string.preferences); - - if (IntentUtils.isIntentAvailable(this, new Intent(AboutMiniIntents.ACTION_SHOW_ABOUT_DIALOG))) { - // Only show "About" dialog, if OI About (or compatible) is installed. - menu.add(0, ABOUT_INDEX, 0, R.string.oi_distribution_about).setIcon( - android.R.drawable.ic_menu_info_details); - } - - return super.onCreateOptionsMenu(menu); - } - - private void addCategoryActivity() { - if (debug) Log.d(TAG,"addCategoryActivity()"); - Intent i = new Intent(this, CategoryEdit.class); - startActivityForResult(i,REQUEST_ADD_CATEGORY); - } - - private void delCategory(long Id) { - if (Passwords.countPasswords(Id)>0) { - Toast.makeText(CategoryList.this, R.string.category_not_empty, - Toast.LENGTH_SHORT).show(); - return; - } - Passwords.deleteCategoryEntry(Id); - fillData(); - } - - public boolean onOptionsItemSelected(MenuItem item) { - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - - AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); - int position=-1; - if (info==null) { - position=getSelectedItemPosition(); - } else { - // used when this is called from a ContextMenu - position=info.position; - } - switch(item.getItemId()) { - case LOCK_CATEGORY_INDEX: - lockAndShutFrontDoor(); - break; - case OPEN_CATEGORY_INDEX: - launchPassList(rows.get(info.position).id); - break; - case EDIT_CATEGORY_INDEX: - if (position > -1) { - Intent i = new Intent(this, CategoryEdit.class); - i.putExtra(KEY_ID, rows.get(position).id); - startActivityForResult(i,REQUEST_EDIT_CATEGORY); - - lastPosition=position; - } - break; - case ADD_CATEGORY_INDEX: - addCategoryActivity(); - break; - case DEL_CATEGORY_INDEX: - try { - if (position > -1) { - delCategory(rows.get(position).id); - if (position>2) { - setSelection(position-1); - } - } - } catch (IndexOutOfBoundsException e) { - // This should only happen when there are no - // entries to delete. - Log.w(TAG,e.toString()); - } - break; - case HELP_INDEX: - Intent help = new Intent(this, Help.class); - startActivity(help); - break; - case SEARCH_INDEX: - onSearchRequested(); - break; - case EXPORT_INDEX: - Dialog exportDialog = new AlertDialog.Builder(CategoryList.this) - .setIcon(R.drawable.passicon) - .setTitle(R.string.export_database) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - exportDatabase(); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }) - .setMessage(R.string.export_msg) - .create(); - exportDialog.show(); - break; - case IMPORT_INDEX: - importDatabase(); - break; - case CHANGE_PASS_INDEX: - Intent changePass = new Intent(this, ChangePass.class); - startActivity(changePass); - break; - case BACKUP_INDEX: - backupThreadStart(); - break; - case RESTORE_INDEX: - restoreDatabase(); - break; - case PREFERENCES_INDEX: - Intent preferences = new Intent(this, Preferences.class); - startActivity(preferences); - break; - case ABOUT_INDEX: - AboutDialog.showDialogOrStartActivity(this, ABOUT_KEY); - break; - default: - Log.e(TAG,"Unknown itemId"); - break; - } - return super.onOptionsItemSelected(item); - } - - private void launchPassList(long id) { - Intent passList = new Intent(this, PassList.class); - passList.putExtra(KEY_ID, id); - startActivityForResult(passList,REQUEST_OPEN_CATEGORY); - } - - private String backupDatabase(String filename, OutputStream str){ - Backup backup=new Backup(this); - backup.write(filename, str); - return backup.getResult(); - } - - - private void lockAndShutFrontDoor () { + private AlertDialog autobackupDialog; + + private boolean lockOnScreenLock = true; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + if (debug) { + Log.d(TAG, "caught ACTION_SCREEN_OFF"); + } + if (lockOnScreenLock) { + Master.setMasterKey(null); + } + } else if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + lockAndShutFrontDoor(); + } + } + }; + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + if (debug) { + Log.d(TAG, "onCreate(" + icicle + ")"); + } + + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + Passwords.Initialize(this); + + setContentView(R.layout.cat_list); + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.categories); + setTitle(title); + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + + final ListView list = getListView(); + list.setFocusable(true); + list.setOnCreateContextMenuListener(this); + list.setTextFilterEnabled(true); + registerForContextMenu(list); + } + + @Override + protected void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + + if (isSignedIn() == false) { + Intent frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + + showFirstTimeWarningDialog(); + if (Passwords.getPrePopulate() == true) { + prePopulate(); + Passwords.clearPrePopulate(); + } + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + lockOnScreenLock = sp.getBoolean(Preferences.PREFERENCE_LOCK_ON_SCREEN_LOCK, true); + + if (taskImport != null) { + // taskImport still running + taskImport.setActivity(this); + startImportProgressDialog(); + return; + } + Passwords.Initialize(this); + + ListAdapter la = getListAdapter(); + if (la != null) { + if (debug) { + Log.d(TAG, "onResume: count=" + la.getCount()); + } + } else { + if (debug) { + Log.d(TAG, "onResume: no list"); + } + fillData(); + } + checkForAutoBackup(); + } + + private void checkForAutoBackup() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + boolean prefAutobackup = sp.getBoolean(Preferences.PREFERENCE_AUTOBACKUP, true); + + if (prefAutobackup == false) { + return; + } + if (Passwords.countPasswords(-1) < 1) { + // if no passwords populated yet, then nevermind + return; + } + TimeZone tz = TimeZone.getDefault(); + int julianDay = Time.getJulianDay((new Date()).getTime(), tz.getRawOffset()); + + SharedPreferences.Editor editor = sp.edit(); + + int lastAutobackupCheck = sp.getInt(Preferences.PREFERENCE_LAST_AUTOBACKUP_CHECK, 0); + editor.putInt(Preferences.PREFERENCE_LAST_AUTOBACKUP_CHECK, julianDay); + editor.commit(); + if (lastAutobackupCheck == 0) { + // first time + if (debug) { + Log.d(TAG, "first time autobackup"); + } + return; + } + int lastBackupJulian = sp.getInt(Preferences.PREFERENCE_LAST_BACKUP_JULIAN, 0); + String maxDaysToAutobackupString = sp.getString( + Preferences.PREFERENCE_AUTOBACKUP_DAYS, + Preferences.PREFERENCE_AUTOBACKUP_DAYS_DEFAULT_VALUE + ); + int maxDaysToAutobackup = 7; + try { + maxDaysToAutobackup = Integer.valueOf(maxDaysToAutobackupString); + } catch (NumberFormatException e) { + Log.d(TAG, "why is autobackup_days busted?"); + } + + int daysSinceLastBackup = julianDay - lastBackupJulian; + if (((julianDay - lastAutobackupCheck) > (maxDaysToAutobackup - 1)) && + ((daysSinceLastBackup) > (maxDaysToAutobackup - 1))) { + if (debug) { + Log.d(TAG, "in need of backup"); + } + // used a custom layout in order to get the checkbox + AlertDialog.Builder builder; + + LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE); + View layout = inflater.inflate(R.layout.auto_backup, null); + + builder = new AlertDialog.Builder(this); + builder.setView(layout); + builder.setTitle(getString(R.string.autobackup)); + builder.setIcon(android.R.drawable.ic_menu_save); + builder.setNegativeButton( + R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + checkAutobackupTurnoff(); + } + } + ); + builder.setPositiveButton( + R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + checkAutobackupTurnoff(); + backupThreadStart(); + } + } + ); + if (daysSinceLastBackup == julianDay) { + builder.setMessage(R.string.backup_never); + } else { + String backupInDays = String.format(getString(R.string.backup_in_days), daysSinceLastBackup); + builder.setMessage(backupInDays); + } + autobackupDialog = builder.create(); + autobackupDialog.show(); + } + } + + private void checkAutobackupTurnoff() { + CheckBox autobackupTurnoff = (CheckBox) autobackupDialog.findViewById(R.id.autobackup_turnoff); + if (autobackupTurnoff.isChecked()) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(Preferences.PREFERENCE_AUTOBACKUP, false); + editor.commit(); + } + } + + /** + * + */ + private void showFirstTimeWarningDialog() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + boolean firstTimeWarning = sp.getBoolean(Preferences.PREFERENCE_FIRST_TIME_WARNING, false); + + if (!firstTimeWarning) { + Intent i = new Intent(this, DialogHostingActivity.class); + i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_FIRST_TIME_WARNING); + startActivity(i); + + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(Preferences.PREFERENCE_FIRST_TIME_WARNING, true); + editor.commit(); + } + } + + @Override + protected void onPause() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onPause()"); + } + + if (taskImport != null) { + importProgress.dismiss(); + taskImport.setActivity(null); + } + if (taskBackup != null) { + backupProgress.dismiss(); + taskBackup.setActivity(null); + } + + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + public void onStop() { + super.onStop(); + + if (debug) { + Log.d(TAG, "onStop()"); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (debug) { + Log.d(TAG, "onDestroy()"); + } + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, + ContextMenuInfo menuInfo) { + + AdapterView.AdapterContextMenuInfo info; + info = (AdapterView.AdapterContextMenuInfo) menuInfo; + + menu.setHeaderTitle(rows.get(info.position).plainName); + menu.add(0, OPEN_CATEGORY_INDEX, 0, R.string.open) + .setIcon(android.R.drawable.ic_menu_view) + .setAlphabeticShortcut('o'); + menu.add(0, EDIT_CATEGORY_INDEX, 0, R.string.password_edit) + .setIcon(android.R.drawable.ic_menu_edit) + .setAlphabeticShortcut('e'); + menu.add(0, DEL_CATEGORY_INDEX, 0, R.string.password_delete) + .setIcon(android.R.drawable.ic_menu_delete) + .setAlphabeticShortcut('d'); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + onOptionsItemSelected(item); + return true; + } + + @Override + protected Dialog onCreateDialog(int id) { + switch (id) { + case ABOUT_KEY: + return new AboutDialog(this); + } + return null; + } + + /** + * Returns the current status of signedIn. + * + * @return True if signed in + */ + public static boolean isSignedIn() { + if ((Master.getSalt() != null) && (Master.getMasterKey() != null)) { + if (debug) { + Log.d(TAG, "isSignedIn: true"); + } + return true; + } + if (debug) { + Log.d(TAG, "isSignedIn: false"); + } + return false; + } + + /** + * Sets signedIn status to false. + * + * @see org.openintents.safe.CategoryList#isSignedIn + */ + public static void setSignedOut() { + if (debug) { + Log.d(TAG, "setSignedOut()"); + } + Master.setMasterKey(null); + } + + /** + * Populates the category ListView + */ + private void fillData() { + if (debug) { + Log.d(TAG, "fillData()"); + } + + rows = Passwords.getCategoryEntries(); + if (debug) { + Log.d(TAG, "fillData: rows=" + rows.size()); + } + + catAdapter = + new CategoryListItemAdapter( + this, R.layout.cat_row, + rows + ); + setListAdapter(catAdapter); + + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + if (menu == null) { + return super.onMenuOpened(featureId, menu); + } + MenuItem miDelete = menu.findItem(DEL_CATEGORY_INDEX); + MenuItem miEdit = menu.findItem(EDIT_CATEGORY_INDEX); + if (getSelectedItemPosition() > -1) { + miDelete.setEnabled(true); + miEdit.setEnabled(true); + } else { + miDelete.setEnabled(false); + miEdit.setEnabled(false); + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + MenuItem item = menu.add(0, LOCK_CATEGORY_INDEX, 0, R.string.password_lock) + .setIcon(android.R.drawable.ic_lock_lock) + .setShortcut('0', 'l'); + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar.showIfRoom(item); + } + + menu.add(0, EDIT_CATEGORY_INDEX, 0, R.string.password_edit) + .setIcon(android.R.drawable.ic_menu_edit) + .setShortcut('1', 'e'); + + menu.add(0, ADD_CATEGORY_INDEX, 0, R.string.password_add) + .setIcon(android.R.drawable.ic_menu_add) + .setShortcut('2', 'a'); + + item = menu.add(0, SEARCH_INDEX, 0, R.string.search) + .setIcon(android.R.drawable.ic_menu_search); + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar.showIfRoom(item); + } + + menu.add(0, DEL_CATEGORY_INDEX, 0, R.string.password_delete) + .setIcon(android.R.drawable.ic_menu_delete) + .setEnabled(false); + + menu.add(0, HELP_INDEX, 0, R.string.help) + .setIcon(android.R.drawable.ic_menu_help); + + menu.add(0, EXPORT_INDEX, 0, R.string.export_database) + .setIcon(android.R.drawable.ic_menu_upload); + menu.add(0, IMPORT_INDEX, 0, R.string.import_database) + .setIcon(android.R.drawable.ic_input_get); + + menu.add(0, CHANGE_PASS_INDEX, 0, R.string.change_password) + .setIcon(android.R.drawable.ic_menu_manage); + + menu.add(0, BACKUP_INDEX, 0, R.string.backup); + menu.add(0, RESTORE_INDEX, 0, R.string.restore); + + menu.add(0, PREFERENCES_INDEX, 0, R.string.preferences); + + if (IntentUtils.isIntentAvailable(this, new Intent(AboutMiniIntents.ACTION_SHOW_ABOUT_DIALOG))) { + // Only show "About" dialog, if OI About (or compatible) is installed. + menu.add(0, ABOUT_INDEX, 0, R.string.oi_distribution_about).setIcon( + android.R.drawable.ic_menu_info_details + ); + } + + return super.onCreateOptionsMenu(menu); + } + + private void addCategoryActivity() { + if (debug) { + Log.d(TAG, "addCategoryActivity()"); + } + Intent i = new Intent(this, CategoryEdit.class); + startActivityForResult(i, REQUEST_ADD_CATEGORY); + } + + private void delCategory(long Id) { + if (Passwords.countPasswords(Id) > 0) { + Toast.makeText( + CategoryList.this, R.string.category_not_empty, + Toast.LENGTH_SHORT + ).show(); + return; + } + Passwords.deleteCategoryEntry(Id); + fillData(); + } + + public boolean onOptionsItemSelected(MenuItem item) { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); + int position = -1; + if (info == null) { + position = getSelectedItemPosition(); + } else { + // used when this is called from a ContextMenu + position = info.position; + } + switch (item.getItemId()) { + case LOCK_CATEGORY_INDEX: + lockAndShutFrontDoor(); + break; + case OPEN_CATEGORY_INDEX: + launchPassList(rows.get(info.position).id); + break; + case EDIT_CATEGORY_INDEX: + if (position > -1) { + Intent i = new Intent(this, CategoryEdit.class); + i.putExtra(KEY_ID, rows.get(position).id); + startActivityForResult(i, REQUEST_EDIT_CATEGORY); + + lastPosition = position; + } + break; + case ADD_CATEGORY_INDEX: + addCategoryActivity(); + break; + case DEL_CATEGORY_INDEX: + try { + if (position > -1) { + delCategory(rows.get(position).id); + if (position > 2) { + setSelection(position - 1); + } + } + } catch (IndexOutOfBoundsException e) { + // This should only happen when there are no + // entries to delete. + Log.w(TAG, e.toString()); + } + break; + case HELP_INDEX: + Intent help = new Intent(this, Help.class); + startActivity(help); + break; + case SEARCH_INDEX: + onSearchRequested(); + break; + case EXPORT_INDEX: + Dialog exportDialog = new AlertDialog.Builder(CategoryList.this) + .setIcon(R.drawable.passicon) + .setTitle(R.string.export_database) + .setPositiveButton( + R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + exportDatabase(); + } + } + ) + .setNegativeButton( + R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + } + ) + .setMessage(R.string.export_msg) + .create(); + exportDialog.show(); + break; + case IMPORT_INDEX: + importDatabase(); + break; + case CHANGE_PASS_INDEX: + Intent changePass = new Intent(this, ChangePass.class); + startActivity(changePass); + break; + case BACKUP_INDEX: + backupThreadStart(); + break; + case RESTORE_INDEX: + restoreDatabase(); + break; + case PREFERENCES_INDEX: + Intent preferences = new Intent(this, Preferences.class); + startActivity(preferences); + break; + case ABOUT_INDEX: + AboutDialog.showDialogOrStartActivity(this, ABOUT_KEY); + break; + default: + Log.e(TAG, "Unknown itemId"); + break; + } + return super.onOptionsItemSelected(item); + } + + private void launchPassList(long id) { + Intent passList = new Intent(this, PassList.class); + passList.putExtra(KEY_ID, id); + startActivityForResult(passList, REQUEST_OPEN_CATEGORY); + } + + private String backupDatabase(String filename, OutputStream str) { + Backup backup = new Backup(this); + backup.write(filename, str); + return backup.getResult(); + } + + private void lockAndShutFrontDoor() { /* Clear the clipboard, if it contains the last password used */ - ClipboardManager cb = ClipboardManager.newInstance(getApplication()); - if (cb.hasText()) { - String clipboardText = cb.getText().toString(); - if (clipboardText.equals(Safe.last_used_password)) - cb.setText(""); - } - - Master.setMasterKey(null); - - Intent autoLockIntent = new Intent(getApplicationContext(), AutoLockService.class); - stopService(autoLockIntent); - - Intent frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - startActivity(frontdoor); - } - - /** - * Start a separate thread to backup the database. By running - * the backup in a thread it allows the main UI thread to return - * and permit the updating of the progress dialog. - */ - private void backupThreadStart(){ - String filename = Preferences.getBackupPath(this); + ClipboardManager cb = ClipboardManager.newInstance(getApplication()); + if (cb.hasText()) { + String clipboardText = cb.getText().toString(); + if (clipboardText.equals(Safe.last_used_password)) { + cb.setText(""); + } + } + + Master.setMasterKey(null); + + Intent autoLockIntent = new Intent(getApplicationContext(), AutoLockService.class); + stopService(autoLockIntent); + + Intent frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + startActivity(frontdoor); + } + + /** + * Start a separate thread to backup the database. By running + * the backup in a thread it allows the main UI thread to return + * and permit the updating of the progress dialog. + */ + private void backupThreadStart() { + String filename = Preferences.getBackupPath(this); Intent intent; int requestId; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { intent = Intents.createCreateDocumentIntent(); requestId = REQUEST_BACKUP_DOCUMENT; } else { intent = Intents.createPickFileIntent(filename, R.string.import_file_select); - requestId = REQUEST_BACKUP_FILENAME; + requestId = REQUEST_BACKUP_FILENAME; } - if(intentCallable(intent)) - startActivityForResult(intent,requestId); - else { + if (intentCallable(intent)) { + startActivityForResult(intent, requestId); + } else { backupToFile(filename); } - } - + } private class backupTask extends AsyncTask { - CategoryList currentActivity=null; - public void setActivity(CategoryList cat) { - currentActivity=cat; - } + CategoryList currentActivity = null; + + public void setActivity(CategoryList cat) { + currentActivity = cat; + } @Override protected String doInBackground(OutputStreamData... streams) { @@ -684,16 +737,16 @@ protected String doInBackground(OutputStreamData... streams) { return response; } - @Override - protected void onPostExecute(String result) { + @Override + protected void onPostExecute(String result) { showResultToast(result); if ((currentActivity != null) - && (currentActivity.backupProgress != null)) { - currentActivity.backupProgress.dismiss(); - } - taskBackup=null; - } - } + && (currentActivity.backupProgress != null)) { + currentActivity.backupProgress.dismiss(); + } + taskBackup = null; + } + } private void showResultToast(String result) { Toast.makeText(this, result, Toast.LENGTH_LONG).show(); @@ -719,539 +772,585 @@ private void backupToDocument(Uri documentUri) { } } + public void backupToFile(OutputStreamData streamData) { - if (taskBackup!=null) { - // there's already a running backup - return; - } - startBackupProgressDialog(); - taskBackup = new backupTask(); - taskBackup.setActivity(this); - taskBackup.execute(streamData); - } - - - private void startBackupProgressDialog() { - if (backupProgress == null) { - backupProgress = new ProgressDialog( - CategoryList.this); - backupProgress.setMessage(getString(R.string.backup_progress) + " " - + Preferences.getBackupPath(CategoryList.this)); - backupProgress.setIndeterminate(false); - backupProgress.setCancelable(false); - } - backupProgress.show(); - } - - private void restoreDatabase(){ - Intent i = new Intent(this, Restore.class); - startActivityForResult(i,REQUEST_RESTORE); - } - - protected void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - launchPassList(rows.get(position).id); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent i) { - super.onActivityResult(requestCode, resultCode, i); - - String path; + if (taskBackup != null) { + // there's already a running backup + return; + } + startBackupProgressDialog(); + taskBackup = new backupTask(); + taskBackup.setActivity(this); + taskBackup.execute(streamData); + } + + private void startBackupProgressDialog() { + if (backupProgress == null) { + backupProgress = new ProgressDialog( + CategoryList.this + ); + backupProgress.setMessage( + getString(R.string.backup_progress) + " " + + Preferences.getBackupPath(CategoryList.this) + ); + backupProgress.setIndeterminate(false); + backupProgress.setCancelable(false); + } + backupProgress.show(); + } + + private void restoreDatabase() { + Intent i = new Intent(this, Restore.class); + startActivityForResult(i, REQUEST_RESTORE); + } + + protected void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + launchPassList(rows.get(position).id); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + + String path; /* Don't know what it is good for, just necessary * to get the same behavior as the one before this patch*/ - if(resultCode == RESULT_OK - && requestCode == REQUEST_ONCREATE - || requestCode == REQUEST_EDIT_CATEGORY - || requestCode == REQUEST_ADD_CATEGORY - || requestCode == REQUEST_OPEN_CATEGORY - || requestCode == REQUEST_RESTORE) - fillData(); - - switch(requestCode){ - case REQUEST_EDIT_CATEGORY: - if(resultCode==RESULT_OK) - setSelection(lastPosition); - break; - - case REQUEST_OPEN_CATEGORY: - // update in case passwords were added/deleted and caused the counts to update - if (catAdapter!=null) - catAdapter.notifyDataSetChanged(); - break; - - case REQUEST_BACKUP_FILENAME: - if(resultCode == RESULT_OK){ - path = i.getData().getPath(); - backupToFile(path); - Preferences.setBackupPathAndMethod(this, path); - } - break; - case REQUEST_BACKUP_DOCUMENT: - if(resultCode == RESULT_OK){ - backupToDocument(i.getData()); - Preferences.setBackupDocumentAndMethod(this, i.getDataString()); + if (resultCode == RESULT_OK + && requestCode == REQUEST_ONCREATE + || requestCode == REQUEST_EDIT_CATEGORY + || requestCode == REQUEST_ADD_CATEGORY + || requestCode == REQUEST_OPEN_CATEGORY + || requestCode == REQUEST_RESTORE) { + fillData(); + } + + switch (requestCode) { + case REQUEST_EDIT_CATEGORY: + if (resultCode == RESULT_OK) { + setSelection(lastPosition); + } + break; + + case REQUEST_OPEN_CATEGORY: + // update in case passwords were added/deleted and caused the counts to update + if (catAdapter != null) { + catAdapter.notifyDataSetChanged(); + } + break; + + case REQUEST_BACKUP_FILENAME: + if (resultCode == RESULT_OK) { + path = i.getData().getPath(); + backupToFile(path); + Preferences.setBackupPathAndMethod(this, path); + } + break; + case REQUEST_BACKUP_DOCUMENT: + if (resultCode == RESULT_OK) { + backupToDocument(i.getData()); + Preferences.setBackupDocumentAndMethod(this, i.getDataString()); + } + break; + + case REQUEST_EXPORT_FILENAME: + if (resultCode == RESULT_OK) { + path = i.getData().getPath(); + exportDatabaseToFile(path); + Preferences.setExportPath(this, path); + } + break; + + case REQUEST_IMPORT_FILENAME: + if (resultCode == RESULT_OK) { + path = i.getData().getPath(); + importFile(path); + Preferences.setExportPath(this, path); + } + break; + } + } + + private void prePopulate() { + addCategory(getString(R.string.category_business)); + addCategory(getString(R.string.category_personal)); + } + + private long addCategory(String name) { + if (debug) { + Log.d(TAG, "addCategory(" + name + ")"); + } + if ((name == null) || (name == "")) { + return -1; + } + CategoryEntry entry = new CategoryEntry(); + entry.plainName = name; + + return Passwords.putCategoryEntry(entry); + } + + public void exportDatabase() { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + String filename = Preferences.getExportPath(this); + + Intent intent = new Intent("org.openintents.action.PICK_FILE"); + intent.setData(Uri.parse("file://" + filename)); + intent.putExtra("org.openintents.extra.TITLE", R.string.export_file_select); + if (intentCallable(intent)) { + startActivityForResult(intent, REQUEST_EXPORT_FILENAME); + } else { + exportDatabaseToFile(filename); + } + } + + private void exportDatabaseToFile(final String filename) { + try { + CSVWriter writer = new CSVWriter(new FileWriter(filename), ','); + + String[] header = {getString(R.string.category), + getString(R.string.description), + getString(R.string.website), + getString(R.string.username), + getString(R.string.password), + getString(R.string.notes), + getString(R.string.last_edited) + }; + writer.writeNext(header); + + HashMap categories = Passwords.getCategoryIdToName(); + + List rows; + rows = Passwords.getPassEntries(Long.valueOf(0), true, false); + + for (PassEntry row : rows) { + String[] rowEntries = {categories.get(row.category), + row.plainDescription, + row.plainWebsite, + row.plainUsername, + row.plainPassword, + row.plainNote, + row.lastEdited + }; + writer.writeNext(rowEntries); } - break; - - case REQUEST_EXPORT_FILENAME: - if(resultCode == RESULT_OK){ - path = i.getData().getPath(); - exportDatabaseToFile(path); - Preferences.setExportPath(this, path); - } - break; - - case REQUEST_IMPORT_FILENAME: - if(resultCode == RESULT_OK){ - path = i.getData().getPath(); - importFile(path); - Preferences.setExportPath(this, path); - } - break; - } - } - - private void prePopulate() { - addCategory(getString(R.string.category_business)); - addCategory(getString(R.string.category_personal)); - } - - private long addCategory(String name) { - if (debug) Log.d(TAG,"addCategory("+name+")"); - if ((name==null) || (name=="")) return -1; - CategoryEntry entry = new CategoryEntry(); - entry.plainName=name; - - return Passwords.putCategoryEntry(entry); - } - - public void exportDatabase(){ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - String filename=Preferences.getExportPath(this); - - Intent intent = new Intent("org.openintents.action.PICK_FILE"); - intent.setData(Uri.parse("file://"+filename)); - intent.putExtra("org.openintents.extra.TITLE", R.string.export_file_select); - if(intentCallable(intent)) - startActivityForResult(intent, REQUEST_EXPORT_FILENAME); - else - exportDatabaseToFile(filename); - } - - private void exportDatabaseToFile(final String filename){ - try { - CSVWriter writer = new CSVWriter(new FileWriter(filename), ','); - - String[] header = { getString(R.string.category), - getString(R.string.description), - getString(R.string.website), - getString(R.string.username), - getString(R.string.password), - getString(R.string.notes), - getString(R.string.last_edited) - }; - writer.writeNext(header); - - HashMap categories = Passwords.getCategoryIdToName(); - - List rows; - rows = Passwords.getPassEntries(Long.valueOf(0), true, false); - - for (PassEntry row : rows) { - String[] rowEntries = { categories.get(row.category), - row.plainDescription, - row.plainWebsite, - row.plainUsername, - row.plainPassword, - row.plainNote, - row.lastEdited - }; - writer.writeNext(rowEntries); - } - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - Toast.makeText(CategoryList.this, R.string.export_file_error, - Toast.LENGTH_SHORT).show(); - return; - } - String msg=getString(R.string.export_success, filename); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + Toast.makeText( + CategoryList.this, R.string.export_file_error, + Toast.LENGTH_SHORT + ).show(); + return; + } + String msg = getString(R.string.export_success, filename); showResultToast(msg); } - private void deleteDatabaseNow(){ - Passwords.deleteAll(); - } + private void deleteDatabaseNow() { + Passwords.deleteAll(); + } - public void deleteDatabase4Import(final String filename){ + public void deleteDatabase4Import(final String filename) { // Log.i(TAG,"deleteDatabase4Import"); - Dialog about = new AlertDialog.Builder(this) - .setIcon(R.drawable.passicon) - .setTitle(R.string.dialog_delete_database_title) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - deleteDatabaseNow(); - importDeletedDatabase=true; - performImportFile(filename); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }) - .setMessage(R.string.dialog_delete_database_msg) - .create(); - about.show(); - } - - public void importDatabase(){ - String defaultExportFilename = Preferences.getExportPath(this); - final String filename; - File oiImport = new File(defaultExportFilename); - String pwsFilename = Environment.getExternalStorageDirectory() - .getPath() + PASSWORDSAFE_IMPORT_FILENAME; - File pwsImport = new File(pwsFilename); - if (oiImport.exists() || !pwsImport.exists()) { - filename=defaultExportFilename; - }else{ - filename=pwsFilename; - } - Intent intent = new Intent("org.openintents.action.PICK_FILE"); - intent.setData(Uri.parse("file://"+filename)); - intent.putExtra("org.openintents.extra.TITLE", R.string.import_file_select); - if(intentCallable(intent)) - startActivityForResult(intent, REQUEST_IMPORT_FILENAME); - else - importFile(filename); - } + Dialog about = new AlertDialog.Builder(this) + .setIcon(R.drawable.passicon) + .setTitle(R.string.dialog_delete_database_title) + .setPositiveButton( + R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + deleteDatabaseNow(); + importDeletedDatabase = true; + performImportFile(filename); + } + } + ) + .setNegativeButton( + R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + } + ) + .setMessage(R.string.dialog_delete_database_msg) + .create(); + about.show(); + } + + public void importDatabase() { + String defaultExportFilename = Preferences.getExportPath(this); + final String filename; + File oiImport = new File(defaultExportFilename); + String pwsFilename = Environment.getExternalStorageDirectory() + .getPath() + PASSWORDSAFE_IMPORT_FILENAME; + File pwsImport = new File(pwsFilename); + if (oiImport.exists() || !pwsImport.exists()) { + filename = defaultExportFilename; + } else { + filename = pwsFilename; + } + Intent intent = new Intent("org.openintents.action.PICK_FILE"); + intent.setData(Uri.parse("file://" + filename)); + intent.putExtra("org.openintents.extra.TITLE", R.string.import_file_select); + if (intentCallable(intent)) { + startActivityForResult(intent, REQUEST_IMPORT_FILENAME); + } else { + importFile(filename); + } + } private class importTask extends AsyncTask { - @Override - protected String doInBackground(String... filenames) { - String response = ""; - importDatabaseFromCSV(filenames[0]); - return response; - } - private String importedFilename=""; - private int importedEntries=0; - private String importMessage=""; - - CategoryList currentActivity=null; - /** - * Set the current activity to be used on PostExecute - * - */ - public void setActivity(CategoryList categoryList) { - currentActivity=categoryList; - } - /** - * While running inside a thread, read from a CSV and import into the - * database. - */ - private void importDatabaseFromCSV(String filename) { - if (restartTimerIntent != null) - sendBroadcast(restartTimerIntent); - try { - importMessage = ""; - importedEntries = 0; - - final int recordLength = 6; - CSVReader reader = new CSVReader(new FileReader(filename)); - String[] nextLine; - nextLine = reader.readNext(); - if (nextLine == null) { - importMessage = getString(R.string.import_error_first_line); - return; - } - if (nextLine.length < recordLength) { - importMessage = getString(R.string.import_error_first_line); - return; - } - if ((nextLine[0] - .compareToIgnoreCase(getString(R.string.category)) != 0) - || (nextLine[1] - .compareToIgnoreCase(getString(R.string.description)) != 0) - || (nextLine[2] - .compareToIgnoreCase(getString(R.string.website)) != 0) - || (nextLine[3] - .compareToIgnoreCase(getString(R.string.username)) != 0) - || (nextLine[4] - .compareToIgnoreCase(getString(R.string.password)) != 0) - || (nextLine[5] - .compareToIgnoreCase(getString(R.string.notes)) != 0)) { - importMessage = getString(R.string.import_error_first_line); - return; - } - // Log.i(TAG,"first line is valid"); - - HashMap categoryToId = Passwords - .getCategoryNameToId(); - // - // take a pass through the CSV and collect any new Categories - // - HashMap categoriesFound = new HashMap(); - int categoryCount = 0; - // int line=0; - while ((nextLine = reader.readNext()) != null) { - // line++; - if (isCancelled()) { - if (debug) Log.d(TAG,"cancelled"); - return; - } - // nextLine[] is an array of values from the line - if ((nextLine == null) || (nextLine[0] == "")) { - continue; // skip blank categories - } - if (categoryToId.containsKey(nextLine[0])) { - continue; // don't recreate existing categories - } - // if (debug) - // Log.d(TAG,"line["+line+"] found category ("+nextLine[0]+")"); - Long passwordsInCategory = Long.valueOf(1); - if (categoriesFound.containsKey(nextLine[0])) { - // we've seen this category before, bump its count - passwordsInCategory += categoriesFound.get(nextLine[0]); - } else { - // newly discovered category - categoryCount++; - } - categoriesFound.put(nextLine[0], passwordsInCategory); - if (categoryCount > MAX_CATEGORIES) { - importMessage = getString(R.string.import_too_many_categories); - return; - } - } - if (debug) - Log.d(TAG, "found " + categoryCount + " categories"); - if (categoryCount != 0) { - Set categorySet = categoriesFound.keySet(); - Iterator i = categorySet.iterator(); - while (i.hasNext()) { - addCategory(i.next()); - } - } - reader.close(); - - // re-read the categories to get id's of new categories - categoryToId = Passwords.getCategoryNameToId(); - // - // read the whole file again to import the actual fields - // - reader = new CSVReader(new FileReader(filename)); - nextLine = reader.readNext(); - int newEntries = 0; - int lineNumber = 0; - String lineErrors = ""; - int lineErrorsCount = 0; - final int maxLineErrors = 10; - while ((nextLine = reader.readNext()) != null) { - lineNumber++; - // Log.d(TAG,"lineNumber="+lineNumber); - - if (isCancelled()) { - if (debug) Log.d(TAG,"cancelled"); - return; - } - - // nextLine[] is an array of values from the line - if (nextLine.length < 2) { - if (lineErrorsCount < maxLineErrors) { - lineErrors += "line " - + lineNumber - + ": " - + getString(R.string.import_not_enough_fields) - + "\n"; - lineErrorsCount++; - } - continue; // skip if not enough fields - } - if (nextLine.length < recordLength) { - // if the fields after category and description are - // missing, - // just fill them in - String[] replacement = new String[recordLength]; - for (int i = 0; i < nextLine.length; i++) { - // copy over the fields we did get - replacement[i] = nextLine[i]; - } - for (int i = nextLine.length; i < recordLength; i++) { - // flesh out the rest of the fields - replacement[i] = ""; - } - nextLine = replacement; - } - if ((nextLine == null) || (nextLine[0] == "")) { - if (lineErrorsCount < maxLineErrors) { - lineErrors += "line " + lineNumber + ": " - + getString(R.string.import_blank_category) - + "\n"; - lineErrorsCount++; - } - continue; // skip blank categories - } - String description = nextLine[1]; - if ((description == null) || (description == "")) { - if (lineErrorsCount < maxLineErrors) { - lineErrors += "line " - + lineNumber - + ": " - + getString(R.string.import_blank_description) - + "\n"; - lineErrorsCount++; - } - continue; - } - - PassEntry entry = new PassEntry(); - entry.category = categoryToId.get(nextLine[0]); - entry.plainDescription = description; - entry.plainWebsite = nextLine[2]; - entry.plainUsername = nextLine[3]; - entry.plainPassword = nextLine[4]; - entry.plainNote = nextLine[5]; - entry.id = 0; - Passwords.putPassEntry(entry); - newEntries++; - } - reader.close(); - if (lineErrors != "") { - if (debug) - Log.d(TAG, lineErrors); - } - - importedEntries = newEntries; - if (newEntries == 0) { - importMessage = getString(R.string.import_no_entries); - return; - } else { - importMessage = getString(R.string.added) + " " - + newEntries + " " + getString(R.string.entries); - importedFilename = filename; - } - } catch (IOException e) { - e.printStackTrace(); - importMessage = getString(R.string.import_file_error); - } - } - - @Override - protected void onPostExecute(String result) { - if (currentActivity!=null) { - currentActivity.importProgress.dismiss(); - } - if (importMessage != "") { + @Override + protected String doInBackground(String... filenames) { + String response = ""; + importDatabaseFromCSV(filenames[0]); + return response; + } + + private String importedFilename = ""; + private int importedEntries = 0; + private String importMessage = ""; + + CategoryList currentActivity = null; + + /** + * Set the current activity to be used on PostExecute + */ + public void setActivity(CategoryList categoryList) { + currentActivity = categoryList; + } + + /** + * While running inside a thread, read from a CSV and import into the + * database. + */ + private void importDatabaseFromCSV(String filename) { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + try { + importMessage = ""; + importedEntries = 0; + + final int recordLength = 6; + CSVReader reader = new CSVReader(new FileReader(filename)); + String[] nextLine; + nextLine = reader.readNext(); + if (nextLine == null) { + importMessage = getString(R.string.import_error_first_line); + return; + } + if (nextLine.length < recordLength) { + importMessage = getString(R.string.import_error_first_line); + return; + } + if ((nextLine[0] + .compareToIgnoreCase(getString(R.string.category)) != 0) + || (nextLine[1] + .compareToIgnoreCase(getString(R.string.description)) != 0) + || (nextLine[2] + .compareToIgnoreCase(getString(R.string.website)) != 0) + || (nextLine[3] + .compareToIgnoreCase(getString(R.string.username)) != 0) + || (nextLine[4] + .compareToIgnoreCase(getString(R.string.password)) != 0) + || (nextLine[5] + .compareToIgnoreCase(getString(R.string.notes)) != 0)) { + importMessage = getString(R.string.import_error_first_line); + return; + } + // Log.i(TAG,"first line is valid"); + + HashMap categoryToId = Passwords + .getCategoryNameToId(); + // + // take a pass through the CSV and collect any new Categories + // + HashMap categoriesFound = new HashMap(); + int categoryCount = 0; + // int line=0; + while ((nextLine = reader.readNext()) != null) { + // line++; + if (isCancelled()) { + if (debug) { + Log.d(TAG, "cancelled"); + } + return; + } + // nextLine[] is an array of values from the line + if ((nextLine == null) || (nextLine[0] == "")) { + continue; // skip blank categories + } + if (categoryToId.containsKey(nextLine[0])) { + continue; // don't recreate existing categories + } + // if (debug) + // Log.d(TAG,"line["+line+"] found category ("+nextLine[0]+")"); + Long passwordsInCategory = Long.valueOf(1); + if (categoriesFound.containsKey(nextLine[0])) { + // we've seen this category before, bump its count + passwordsInCategory += categoriesFound.get(nextLine[0]); + } else { + // newly discovered category + categoryCount++; + } + categoriesFound.put(nextLine[0], passwordsInCategory); + if (categoryCount > MAX_CATEGORIES) { + importMessage = getString(R.string.import_too_many_categories); + return; + } + } + if (debug) { + Log.d(TAG, "found " + categoryCount + " categories"); + } + if (categoryCount != 0) { + Set categorySet = categoriesFound.keySet(); + Iterator i = categorySet.iterator(); + while (i.hasNext()) { + addCategory(i.next()); + } + } + reader.close(); + + // re-read the categories to get id's of new categories + categoryToId = Passwords.getCategoryNameToId(); + // + // read the whole file again to import the actual fields + // + reader = new CSVReader(new FileReader(filename)); + nextLine = reader.readNext(); + int newEntries = 0; + int lineNumber = 0; + String lineErrors = ""; + int lineErrorsCount = 0; + final int maxLineErrors = 10; + while ((nextLine = reader.readNext()) != null) { + lineNumber++; + // Log.d(TAG,"lineNumber="+lineNumber); + + if (isCancelled()) { + if (debug) { + Log.d(TAG, "cancelled"); + } + return; + } + + // nextLine[] is an array of values from the line + if (nextLine.length < 2) { + if (lineErrorsCount < maxLineErrors) { + lineErrors += "line " + + lineNumber + + ": " + + getString(R.string.import_not_enough_fields) + + "\n"; + lineErrorsCount++; + } + continue; // skip if not enough fields + } + if (nextLine.length < recordLength) { + // if the fields after category and description are + // missing, + // just fill them in + String[] replacement = new String[recordLength]; + for (int i = 0; i < nextLine.length; i++) { + // copy over the fields we did get + replacement[i] = nextLine[i]; + } + for (int i = nextLine.length; i < recordLength; i++) { + // flesh out the rest of the fields + replacement[i] = ""; + } + nextLine = replacement; + } + if ((nextLine == null) || (nextLine[0] == "")) { + if (lineErrorsCount < maxLineErrors) { + lineErrors += "line " + lineNumber + ": " + + getString(R.string.import_blank_category) + + "\n"; + lineErrorsCount++; + } + continue; // skip blank categories + } + String description = nextLine[1]; + if ((description == null) || (description == "")) { + if (lineErrorsCount < maxLineErrors) { + lineErrors += "line " + + lineNumber + + ": " + + getString(R.string.import_blank_description) + + "\n"; + lineErrorsCount++; + } + continue; + } + + PassEntry entry = new PassEntry(); + entry.category = categoryToId.get(nextLine[0]); + entry.plainDescription = description; + entry.plainWebsite = nextLine[2]; + entry.plainUsername = nextLine[3]; + entry.plainPassword = nextLine[4]; + entry.plainNote = nextLine[5]; + entry.id = 0; + Passwords.putPassEntry(entry); + newEntries++; + } + reader.close(); + if (lineErrors != "") { + if (debug) { + Log.d(TAG, lineErrors); + } + } + + importedEntries = newEntries; + if (newEntries == 0) { + importMessage = getString(R.string.import_no_entries); + return; + } else { + importMessage = getString(R.string.added) + " " + + newEntries + " " + getString(R.string.entries); + importedFilename = filename; + } + } catch (IOException e) { + e.printStackTrace(); + importMessage = getString(R.string.import_file_error); + } + } + + @Override + protected void onPostExecute(String result) { + if (currentActivity != null) { + currentActivity.importProgress.dismiss(); + } + if (importMessage != "") { showResultToast(importMessage); } - if (importedFilename != "") { - String deleteMsg = getString(R.string.import_delete_csv) + " " - + importedFilename + "?"; - Dialog about = new AlertDialog.Builder(CategoryList.this) - .setIcon(R.drawable.passicon) - .setTitle(R.string.import_complete) - .setPositiveButton(R.string.yes, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - File csvFile = new File( - importedFilename); - // csvFile.delete(); - SecureDelete.delete(csvFile); - importedFilename = ""; - } - }) - .setNegativeButton(R.string.no, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - } - }).setMessage(deleteMsg).create(); - about.show(); - } - - if ((importedEntries != 0) || (importDeletedDatabase)) { - if (currentActivity!=null) { - currentActivity.fillData(); - if (currentActivity.importProgress!=null) { - currentActivity.importProgress.dismiss(); - } - } - } - taskImport=null; - } - } - - public void performImportFile(String importFilename) { - startImportProgressDialog(); - taskImport = new importTask(); - taskImport.setActivity(this); - taskImport.execute(new String[] { importFilename }); - } - - private void startImportProgressDialog() { - if (importProgress == null) { - importProgress = new ProgressDialog(this); - importProgress.setMessage(getString(R.string.import_progress)); - importProgress.setIndeterminate(false); - importProgress.setCancelable(false); - } - importProgress.show(); - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (debug) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + if (importedFilename != "") { + String deleteMsg = getString(R.string.import_delete_csv) + " " + + importedFilename + "?"; + Dialog about = new AlertDialog.Builder(CategoryList.this) + .setIcon(R.drawable.passicon) + .setTitle(R.string.import_complete) + .setPositiveButton( + R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + File csvFile = new File( + importedFilename + ); + // csvFile.delete(); + SecureDelete.delete(csvFile); + importedFilename = ""; + } + } + ) + .setNegativeButton( + R.string.no, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + } + } + ).setMessage(deleteMsg).create(); + about.show(); + } + + if ((importedEntries != 0) || (importDeletedDatabase)) { + if (currentActivity != null) { + currentActivity.fillData(); + if (currentActivity.importProgress != null) { + currentActivity.importProgress.dismiss(); + } + } + } + taskImport = null; + } + } + + public void performImportFile(String importFilename) { + startImportProgressDialog(); + taskImport = new importTask(); + taskImport.setActivity(this); + taskImport.execute(new String[]{importFilename}); + } + + private void startImportProgressDialog() { + if (importProgress == null) { + importProgress = new ProgressDialog(this); + importProgress.setMessage(getString(R.string.import_progress)); + importProgress.setIndeterminate(false); + importProgress.setCancelable(false); + } + importProgress.show(); + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // Intent frontdoor = new Intent(this, FrontDoor.class); // frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); // startActivity(frontdoor); - }else{ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } - - public boolean onSearchRequested() { - Intent search = new Intent(this, Search.class); - startActivity(search); - return true; - } - - private boolean intentCallable(Intent intent){ - List list = getPackageManager().queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - return list.size() > 0; - } - - private void importFile(final String filename){ - File csvFile=new File(filename); - if (!csvFile.exists()) { - String msg=getString(R.string.import_file_missing) + " " + - filename; + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } + + public boolean onSearchRequested() { + Intent search = new Intent(this, Search.class); + startActivity(search); + return true; + } + + private boolean intentCallable(Intent intent) { + List list = getPackageManager().queryIntentActivities( + intent, + PackageManager.MATCH_DEFAULT_ONLY + ); + return list.size() > 0; + } + + private void importFile(final String filename) { + File csvFile = new File(filename); + if (!csvFile.exists()) { + String msg = getString(R.string.import_file_missing) + " " + + filename; showResultToast(msg); return; - } - Dialog about = new AlertDialog.Builder(this) - .setIcon(R.drawable.passicon) - .setTitle(R.string.dialog_import_title) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - deleteDatabase4Import(filename); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - importDeletedDatabase=false; - performImportFile(filename); - } - }) - .setMessage(getString(R.string.dialog_import_msg, filename)) - .create(); - about.show(); - } -} \ No newline at end of file + } + Dialog about = new AlertDialog.Builder(this) + .setIcon(R.drawable.passicon) + .setTitle(R.string.dialog_import_title) + .setPositiveButton( + R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + deleteDatabase4Import(filename); + } + } + ) + .setNegativeButton( + R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + importDeletedDatabase = false; + performImportFile(filename); + } + } + ) + .setMessage(getString(R.string.dialog_import_msg, filename)) + .create(); + about.show(); + } +} diff --git a/Safe/src/org/openintents/safe/CategoryListItemAdapter.java b/Safe/src/org/openintents/safe/CategoryListItemAdapter.java index 80f0fa8f..e77bb542 100644 --- a/Safe/src/org/openintents/safe/CategoryListItemAdapter.java +++ b/Safe/src/org/openintents/safe/CategoryListItemAdapter.java @@ -16,10 +16,6 @@ */ package org.openintents.safe; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import android.content.Context; import android.util.Log; import android.view.LayoutInflater; @@ -30,109 +26,114 @@ import android.widget.LinearLayout; import android.widget.TextView; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + /** * @author Randy McEoin - * - * Many thanks to Professional Android Application Development by Reto Meier - * from which this adapter is based upon. + *

+ * Many thanks to Professional Android Application Development by Reto Meier + * from which this adapter is based upon. */ public class CategoryListItemAdapter extends ArrayAdapter { - private static boolean debug = false; - private static final String TAG = "CategoryListItemAdapter"; - private List filteredItems; - private List allItems; - private final Object lock = new Object(); - private Filter filter = null; - - int resource; - - public CategoryListItemAdapter(Context _context, int _resource, - List _items) { - super(_context, _resource, _items); - resource = _resource; - filteredItems = _items; - allItems = new ArrayList(); - for(CategoryEntry item : _items){ - allItems.add(item); - } - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - LinearLayout categoryListView; - - CategoryEntry item = getItem(position); - - String name = item.plainName; - int count = item.count; - - if (convertView == null) { - categoryListView = new LinearLayout(getContext()); - String inflater = Context.LAYOUT_INFLATER_SERVICE; - LayoutInflater vi; - vi = (LayoutInflater)getContext().getSystemService(inflater); - vi.inflate(resource, categoryListView, true); - } else { - categoryListView = (LinearLayout) convertView; - } - - TextView nameView = (TextView)categoryListView.findViewById(R.id.rowName); - TextView countView = (TextView)categoryListView.findViewById(R.id.rowCount); - - if (debug) Log.d(TAG, "count="+count); - nameView.setText(name); - countView.setText(Integer.toString(count)); - - return categoryListView; - } - - @Override - public int getCount(){ - synchronized(lock) { - return filteredItems!=null ? filteredItems.size() : 0; + private static boolean debug = false; + private static final String TAG = "CategoryListItemAdapter"; + private List filteredItems; + private List allItems; + private final Object lock = new Object(); + private Filter filter = null; + + int resource; + + public CategoryListItemAdapter(Context _context, int _resource, + List _items) { + super(_context, _resource, _items); + resource = _resource; + filteredItems = _items; + allItems = new ArrayList(); + for (CategoryEntry item : _items) { + allItems.add(item); } } - + @Override - public boolean isEmpty(){ - return allItems.isEmpty(); + public View getView(int position, View convertView, ViewGroup parent) { + LinearLayout categoryListView; + + CategoryEntry item = getItem(position); + + String name = item.plainName; + int count = item.count; + + if (convertView == null) { + categoryListView = new LinearLayout(getContext()); + String inflater = Context.LAYOUT_INFLATER_SERVICE; + LayoutInflater vi; + vi = (LayoutInflater) getContext().getSystemService(inflater); + vi.inflate(resource, categoryListView, true); + } else { + categoryListView = (LinearLayout) convertView; + } + + TextView nameView = (TextView) categoryListView.findViewById(R.id.rowName); + TextView countView = (TextView) categoryListView.findViewById(R.id.rowCount); + + if (debug) { + Log.d(TAG, "count=" + count); + } + nameView.setText(name); + countView.setText(Integer.toString(count)); + + return categoryListView; + } + + @Override + public int getCount() { + synchronized (lock) { + return filteredItems != null ? filteredItems.size() : 0; + } } @Override - public CategoryEntry getItem(int item){ - CategoryEntry gi = null; - synchronized(lock) { - gi = filteredItems!=null ? filteredItems.get(item) : null; + public boolean isEmpty() { + return allItems.isEmpty(); + } + + @Override + public CategoryEntry getItem(int item) { + CategoryEntry gi = null; + synchronized (lock) { + gi = filteredItems != null ? filteredItems.get(item) : null; } return gi; } - + public Filter getFilter() { - if (filter == null){ + if (filter == null) { filter = new CategoryEntryFilter(); } return filter; - } + } - - private class CategoryEntryFilter extends Filter{ - protected FilterResults performFiltering(CharSequence search){ + private class CategoryEntryFilter extends Filter { + protected FilterResults performFiltering(CharSequence search) { FilterResults results = new FilterResults(); - if (search == null || search.length() == 0){ - synchronized(lock){ + if (search == null || search.length() == 0) { + synchronized (lock) { results.values = allItems; results.count = allItems.size(); } - }else{ - synchronized(lock){ + } else { + synchronized (lock) { String q = search.toString().toLowerCase(); final ArrayList filtered = new ArrayList(); final int count = allItems.size(); - for (int i = 0; i < count; i++){ + for (int i = 0; i < count; i++) { CategoryEntry item = allItems.get(i); String itemName = item.plainName.toLowerCase(); String[] words = itemName.split(" "); @@ -140,7 +141,7 @@ protected FilterResults performFiltering(CharSequence search){ for (int k = 0; k < wordCount; k++) { if (words[k].startsWith(q)) { - filtered.add(item); + filtered.add(item); break; } } @@ -156,13 +157,13 @@ protected FilterResults performFiltering(CharSequence search){ @Override protected void publishResults(CharSequence prefix, FilterResults results) { - synchronized(lock) { + synchronized (lock) { @SuppressWarnings("unchecked") - final ArrayList localItems = (ArrayList) results.values; + final ArrayList localItems = (ArrayList) results.values; clear(); Iterator iterator = localItems.iterator(); - while(iterator.hasNext()){ - CategoryEntry gi = (CategoryEntry) iterator.next(); + while (iterator.hasNext()) { + CategoryEntry gi = (CategoryEntry) iterator.next(); add(gi); } notifyDataSetChanged(); diff --git a/Safe/src/org/openintents/safe/ChangePass.java b/Safe/src/org/openintents/safe/ChangePass.java index fbd0b70b..adc7accb 100644 --- a/Safe/src/org/openintents/safe/ChangePass.java +++ b/Safe/src/org/openintents/safe/ChangePass.java @@ -15,11 +15,6 @@ */ package org.openintents.safe; -import java.util.List; - -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.password.Master; - import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; @@ -32,330 +27,393 @@ import android.widget.EditText; import android.widget.Toast; +import java.util.List; + +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.password.Master; + /** * Allows user to change the password used to unlock the application * as well as encrypt the database. - * + * * @author Randy McEoin */ public class ChangePass extends Activity { - private static boolean debug = false; - private static final String TAG = "ChangePass"; - - String oldPassword; - String newPassword; - - Intent frontdoor; - private Intent restartTimerIntent=null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - if (debug) Log.d(TAG,"onCreate()"); - - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent (CryptoIntents.ACTION_RESTART_TIMER); - - setContentView(R.layout.chg_pass); - String title = getResources().getString(R.string.app_name) + " - " + - getResources().getString(R.string.change_password); - setTitle(title); - - Button changePasswordButton = (Button) findViewById(R.id.change_password_button); - - changePasswordButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - performChangePass(); - } - }); - - } - - @Override - protected void onPause() { - super.onPause(); - - if (debug) Log.d(TAG,"onPause()"); - - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (debug) Log.d(TAG,"onResume()"); - - if (CategoryList.isSignedIn()==false) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - - Passwords.Initialize(this); - } - - /** - * Check the old, new and verify fields then try to re-encrypt - * the data. - */ - private void performChangePass() { - if (debug) Log.d(TAG,"performChangePass()"); - - EditText oldPassword = (EditText) findViewById(R.id.old_password); - EditText newPassword = (EditText) findViewById(R.id.new_password); - EditText verifyPassword = (EditText) findViewById(R.id.verify_password); - - String oldPlain = oldPassword.getText().toString(); - String newPlain = newPassword.getText().toString(); - String verifyPlain = verifyPassword.getText().toString(); - - if (newPlain.compareTo(verifyPlain) != 0) { - Toast.makeText(ChangePass.this, R.string.new_verify_mismatch, - Toast.LENGTH_SHORT).show(); - return; - } - if (newPlain.length() < 4) { - Toast.makeText(ChangePass.this, R.string.notify_blank_pass, - Toast.LENGTH_SHORT).show(); - return; - } - if (!checkUserPassword(oldPlain)) { - Toast.makeText(ChangePass.this, R.string.invalid_old_password, - Toast.LENGTH_SHORT).show(); - return; - } - changeMasterPassword(oldPlain, newPlain); - } - - private boolean changeMasterPassword(String oldPass, String newPass) { - - DBHelper dbHelper= new DBHelper(this); - - CryptoHelper ch = new CryptoHelper(); - - String encryptedMasterKey = dbHelper.fetchMasterKey(); - String decryptedMasterKey = ""; - try { - ch.init(CryptoHelper.EncryptionStrong, dbHelper.fetchSalt()); - ch.setPassword(oldPass); - decryptedMasterKey = ch.decrypt(encryptedMasterKey); - if (ch.getStatus()==true) { // successful decryption? - ch.setPassword(newPass); - encryptedMasterKey = ch.encrypt(decryptedMasterKey); - if (ch.getStatus()==true) { // successful encryption? - dbHelper.storeMasterKey(encryptedMasterKey); - Passwords.InitCrypto(CryptoHelper.EncryptionMedium, dbHelper.fetchSalt(), decryptedMasterKey); - Passwords.Reset(); - dbHelper.close(); - Toast.makeText(ChangePass.this, R.string.password_changed, - Toast.LENGTH_LONG).show(); - setResult(RESULT_OK); - finish(); - return true; - } - } - - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString()); - Toast.makeText(this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - Log.e(TAG, e.toString()); - Toast.makeText(this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - } - - dbHelper.close(); - - Toast.makeText(ChangePass.this, R.string.error_changing_password, - Toast.LENGTH_LONG).show(); - return false; - } - - /** - * This is an older function. We'll want to re-use this when we - * allow the user to regenerate the master key. - * - * @param oldPass - * @param newPass - */ - public void changePassword(String oldPass, String newPass) { - if (debug) Log.d(TAG,"changePassword(,)"); - - DBHelper dbHelper= new DBHelper(this); - - CryptoHelper ch = new CryptoHelper(); - - List categoryRows; - categoryRows = dbHelper.fetchAllCategoryRows(); - - List passRows; - passRows = dbHelper.fetchAllRows(Long.valueOf(0)); - - /** - * Decrypt everything using the old password. - */ - if (debug) Log.d(TAG,"decrypting"); - ch.setPassword(oldPass); - - for (CategoryEntry row : categoryRows) { - row.plainName = ""; - try { - row.plainName = ch.decrypt(row.name); - } catch (CryptoHelperException e) { - if (debug) Log.e(TAG,e.toString()); - Toast.makeText(this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - } - - for (PassEntry row : passRows) { - try { - row.plainDescription = ch.decrypt(row.description); - row.plainWebsite = ch.decrypt(row.website); - row.plainUsername = ch.decrypt(row.username); - row.plainPassword = ch.decrypt(row.password); - row.plainNote = ch.decrypt(row.note); - } catch (CryptoHelperException e) { - if (debug) Log.e(TAG,e.toString()); - Toast.makeText(this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - } - - /** - * Encrypt everything using the new password. - */ - if (debug) Log.d(TAG,"encrypting"); - ch.setPassword(newPass); - - for (CategoryEntry row : categoryRows) { - try { - row.name = ch.encrypt(row.plainName); - } catch (CryptoHelperException e) { - if (debug) Log.e(TAG,e.toString()); - Toast.makeText(this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - } - - for (PassEntry row : passRows) { - try { - row.description = ch.encrypt(row.plainDescription); - row.website = ch.encrypt(row.plainWebsite); - row.username = ch.encrypt(row.plainUsername); - row.password = ch.encrypt(row.plainPassword); - row.note = ch.encrypt(row.plainNote); - } catch (CryptoHelperException e) { - if (debug) Log.e(TAG,e.toString()); - Toast.makeText(this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - } - - /** - * Update the database with the newly encrypted data. - */ - if (debug) Log.d(TAG,"updating database"); - dbHelper.beginTransaction(); - - for (CategoryEntry row : categoryRows) { - dbHelper.updateCategory(row.id, row); - } - - for (PassEntry row : passRows) { - dbHelper.updatePassword(row.id, row); - } - - byte[] md5Key = CryptoHelper.md5String(newPass); - String hexKey = CryptoHelper.toHexString(md5Key); - String cryptKey = ""; - Log.i(TAG, "Saving Password: " + hexKey); - try { - cryptKey = ch.encrypt(hexKey); - dbHelper.storeMasterKey(cryptKey); - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString()); - Toast.makeText(this,getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - dbHelper.rollback(); - dbHelper.close(); - return; - } - - dbHelper.commit(); - - Master.setMasterKey(newPass); - - dbHelper.close(); - } - - /** - * Check the provided clear text password with the one stored - * in the database. - * - * @param pass = clear text password - * @return True if password is correct. - */ - private boolean checkUserPassword(String pass) { - if (debug) Log.d(TAG,"checkUserPassword()"); - - DBHelper dbHelper= new DBHelper(this); - String confirmKey = dbHelper.fetchMasterKey(); - - CryptoHelper ch = new CryptoHelper(); - - try { - ch.init(CryptoHelper.EncryptionStrong, dbHelper.fetchSalt()); - ch.setPassword(pass); - ch.decrypt(confirmKey); - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString()); - } - dbHelper.close(); - - // was decryption of the master key successful? - if (ch.getStatus()==true) { - return true; // then we must have a good master password - } - return false; - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (debug) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + private static boolean debug = false; + private static final String TAG = "ChangePass"; + + String oldPassword; + String newPassword; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + if (debug) { + Log.d(TAG, "onCreate()"); + } + + frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + setContentView(R.layout.chg_pass); + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.change_password); + setTitle(title); + + Button changePasswordButton = (Button) findViewById(R.id.change_password_button); + + changePasswordButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + performChangePass(); + } + } + ); + + } + + @Override + protected void onPause() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onPause()"); + } + + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + + if (CategoryList.isSignedIn() == false) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + + Passwords.Initialize(this); + } + + /** + * Check the old, new and verify fields then try to re-encrypt + * the data. + */ + private void performChangePass() { + if (debug) { + Log.d(TAG, "performChangePass()"); + } + + EditText oldPassword = (EditText) findViewById(R.id.old_password); + EditText newPassword = (EditText) findViewById(R.id.new_password); + EditText verifyPassword = (EditText) findViewById(R.id.verify_password); + + String oldPlain = oldPassword.getText().toString(); + String newPlain = newPassword.getText().toString(); + String verifyPlain = verifyPassword.getText().toString(); + + if (newPlain.compareTo(verifyPlain) != 0) { + Toast.makeText( + ChangePass.this, R.string.new_verify_mismatch, + Toast.LENGTH_SHORT + ).show(); + return; + } + if (newPlain.length() < 4) { + Toast.makeText( + ChangePass.this, R.string.notify_blank_pass, + Toast.LENGTH_SHORT + ).show(); + return; + } + if (!checkUserPassword(oldPlain)) { + Toast.makeText( + ChangePass.this, R.string.invalid_old_password, + Toast.LENGTH_SHORT + ).show(); + return; + } + changeMasterPassword(oldPlain, newPlain); + } + + private boolean changeMasterPassword(String oldPass, String newPass) { + + DBHelper dbHelper = new DBHelper(this); + + CryptoHelper ch = new CryptoHelper(); + + String encryptedMasterKey = dbHelper.fetchMasterKey(); + String decryptedMasterKey = ""; + try { + ch.init(CryptoHelper.EncryptionStrong, dbHelper.fetchSalt()); + ch.setPassword(oldPass); + decryptedMasterKey = ch.decrypt(encryptedMasterKey); + if (ch.getStatus() == true) { // successful decryption? + ch.setPassword(newPass); + encryptedMasterKey = ch.encrypt(decryptedMasterKey); + if (ch.getStatus() == true) { // successful encryption? + dbHelper.storeMasterKey(encryptedMasterKey); + Passwords.InitCrypto(CryptoHelper.EncryptionMedium, dbHelper.fetchSalt(), decryptedMasterKey); + Passwords.Reset(); + dbHelper.close(); + Toast.makeText( + ChangePass.this, R.string.password_changed, + Toast.LENGTH_LONG + ).show(); + setResult(RESULT_OK); + finish(); + return true; + } + } + + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + } catch (Exception e) { + Log.e(TAG, e.toString()); + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + } + + dbHelper.close(); + + Toast.makeText( + ChangePass.this, R.string.error_changing_password, + Toast.LENGTH_LONG + ).show(); + return false; + } + + /** + * This is an older function. We'll want to re-use this when we + * allow the user to regenerate the master key. + * + * @param oldPass + * @param newPass + */ + public void changePassword(String oldPass, String newPass) { + if (debug) { + Log.d(TAG, "changePassword(,)"); + } + + DBHelper dbHelper = new DBHelper(this); + + CryptoHelper ch = new CryptoHelper(); + + List categoryRows; + categoryRows = dbHelper.fetchAllCategoryRows(); + + List passRows; + passRows = dbHelper.fetchAllRows(Long.valueOf(0)); + + /** + * Decrypt everything using the old password. + */ + if (debug) { + Log.d(TAG, "decrypting"); + } + ch.setPassword(oldPass); + + for (CategoryEntry row : categoryRows) { + row.plainName = ""; + try { + row.plainName = ch.decrypt(row.name); + } catch (CryptoHelperException e) { + if (debug) { + Log.e(TAG, e.toString()); + } + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + return; + } + } + + for (PassEntry row : passRows) { + try { + row.plainDescription = ch.decrypt(row.description); + row.plainWebsite = ch.decrypt(row.website); + row.plainUsername = ch.decrypt(row.username); + row.plainPassword = ch.decrypt(row.password); + row.plainNote = ch.decrypt(row.note); + } catch (CryptoHelperException e) { + if (debug) { + Log.e(TAG, e.toString()); + } + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + return; + } + } + + /** + * Encrypt everything using the new password. + */ + if (debug) { + Log.d(TAG, "encrypting"); + } + ch.setPassword(newPass); + + for (CategoryEntry row : categoryRows) { + try { + row.name = ch.encrypt(row.plainName); + } catch (CryptoHelperException e) { + if (debug) { + Log.e(TAG, e.toString()); + } + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + return; + } + } + + for (PassEntry row : passRows) { + try { + row.description = ch.encrypt(row.plainDescription); + row.website = ch.encrypt(row.plainWebsite); + row.username = ch.encrypt(row.plainUsername); + row.password = ch.encrypt(row.plainPassword); + row.note = ch.encrypt(row.plainNote); + } catch (CryptoHelperException e) { + if (debug) { + Log.e(TAG, e.toString()); + } + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + return; + } + } + + /** + * Update the database with the newly encrypted data. + */ + if (debug) { + Log.d(TAG, "updating database"); + } + dbHelper.beginTransaction(); + + for (CategoryEntry row : categoryRows) { + dbHelper.updateCategory(row.id, row); + } + + for (PassEntry row : passRows) { + dbHelper.updatePassword(row.id, row); + } + + byte[] md5Key = CryptoHelper.md5String(newPass); + String hexKey = CryptoHelper.toHexString(md5Key); + String cryptKey = ""; + Log.i(TAG, "Saving Password: " + hexKey); + try { + cryptKey = ch.encrypt(hexKey); + dbHelper.storeMasterKey(cryptKey); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + dbHelper.rollback(); + dbHelper.close(); + return; + } + + dbHelper.commit(); + + Master.setMasterKey(newPass); + + dbHelper.close(); + } + + /** + * Check the provided clear text password with the one stored + * in the database. + * + * @param pass = clear text password + * @return True if password is correct. + */ + private boolean checkUserPassword(String pass) { + if (debug) { + Log.d(TAG, "checkUserPassword()"); + } + + DBHelper dbHelper = new DBHelper(this); + String confirmKey = dbHelper.fetchMasterKey(); + + CryptoHelper ch = new CryptoHelper(); + + try { + ch.init(CryptoHelper.EncryptionStrong, dbHelper.fetchSalt()); + ch.setPassword(pass); + ch.decrypt(confirmKey); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + dbHelper.close(); + + // was decryption of the master key successful? + if (ch.getStatus() == true) { + return true; // then we must have a good master password + } + return false; + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // startActivity(frontdoor); - }else{ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } } diff --git a/Safe/src/org/openintents/safe/CryptoContentProvider.java b/Safe/src/org/openintents/safe/CryptoContentProvider.java index b47974c0..eefa6479 100644 --- a/Safe/src/org/openintents/safe/CryptoContentProvider.java +++ b/Safe/src/org/openintents/safe/CryptoContentProvider.java @@ -15,9 +15,6 @@ */ package org.openintents.safe; -import java.io.File; -import java.io.FileNotFoundException; - import android.content.ContentProvider; import android.content.ContentValues; import android.content.Intent; @@ -27,58 +24,61 @@ import android.os.ParcelFileDescriptor; import android.util.Log; +import java.io.File; +import java.io.FileNotFoundException; + public class CryptoContentProvider extends ContentProvider { - private static final boolean debug = false; - private static final String TAG = "CryptoContentProvider"; - - public static CryptoHelper ch=null; - - public static final String AUTHORITY = "org.openintents.safe"; - public static final Uri CONTENT_URI - =Uri.parse("content://"+AUTHORITY); - - public static final String SESSION_FILE = "session"; - - private static final int ENCRYPT_ID = 2; - private static final int DECRYPT_ID = 3; - private static final int DECRYPT_FILE_ID = 4; - - private static final UriMatcher sUriMatcher; - - static { - sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - sUriMatcher.addURI(AUTHORITY, "encrypt/*", ENCRYPT_ID); - sUriMatcher.addURI(AUTHORITY, "decrypt/*", DECRYPT_ID); - sUriMatcher.addURI(AUTHORITY, "decryptfile", DECRYPT_FILE_ID); // [Peli] can be renamed to "decrypt/*" if first two options are made obsolete - } - - @Override - public boolean onCreate() { - return true; - } - - @Override - public int delete(Uri uri, String s, String[] as) { - // not supported - return 0; - } - - @Override - public String getType(Uri uri) { - // return file extension (uri.lastIndexOf(".")) - return null; //mMimeTypes.getMimeType(uri.toString()); - } - - @Override - public Uri insert(Uri uri, ContentValues contentvalues) { - // not supported - return null; - } - - @Override - public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) { - /* + private static final boolean debug = false; + private static final String TAG = "CryptoContentProvider"; + + public static CryptoHelper ch = null; + + public static final String AUTHORITY = "org.openintents.safe"; + public static final Uri CONTENT_URI + = Uri.parse("content://" + AUTHORITY); + + public static final String SESSION_FILE = "session"; + + private static final int ENCRYPT_ID = 2; + private static final int DECRYPT_ID = 3; + private static final int DECRYPT_FILE_ID = 4; + + private static final UriMatcher sUriMatcher; + + static { + sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + sUriMatcher.addURI(AUTHORITY, "encrypt/*", ENCRYPT_ID); + sUriMatcher.addURI(AUTHORITY, "decrypt/*", DECRYPT_ID); + sUriMatcher.addURI(AUTHORITY, "decryptfile", DECRYPT_FILE_ID); // [Peli] can be renamed to "decrypt/*" if first two options are made obsolete + } + + @Override + public boolean onCreate() { + return true; + } + + @Override + public int delete(Uri uri, String s, String[] as) { + // not supported + return 0; + } + + @Override + public String getType(Uri uri) { + // return file extension (uri.lastIndexOf(".")) + return null; //mMimeTypes.getMimeType(uri.toString()); + } + + @Override + public Uri insert(Uri uri, ContentValues contentvalues) { + // not supported + return null; + } + + @Override + public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) { + /* if (uri.toString().startsWith( MIME_TYPE_PREFIX)) { MatrixCursor c = new MatrixCursor(new String[] { Images.Media.DATA, @@ -92,111 +92,137 @@ public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) { throw new RuntimeException("Unsupported uri"); } */ - return null; - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) - throws FileNotFoundException { - if (debug) Log.d(TAG,"openFile("+uri.toString()+","+mode+")"); - - ParcelFileDescriptor pfd = null; - try { - // get the /files/ directory for our application, which - // for us is /data/data/org.openintents.safe/files/ - String filesDir=getContext().getFilesDir().toString(); - - String path=filesDir; - String cryptSession; - String sessionFile; - String originalFile; - int modeBits = 0; - switch (sUriMatcher.match(uri)) { - case ENCRYPT_ID: - if (debug) Log.d(TAG,"openFile: ENCRYPT"); - modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY | - ParcelFileDescriptor.MODE_CREATE; - cryptSession = uri.getPathSegments().get(1); - sessionFile=SESSION_FILE+"."+cryptSession; - path += "/"+sessionFile; - break; - case DECRYPT_ID: - if (debug) Log.d(TAG,"openFile: DECRYPT"); - modeBits = ParcelFileDescriptor.MODE_READ_ONLY; - cryptSession = uri.getPathSegments().get(1); - sessionFile=SESSION_FILE+"."+cryptSession; - path += "/"+sessionFile; - break; - case DECRYPT_FILE_ID: - if (debug) Log.d(TAG,"openFile: DECRYPT_FILE"); - modeBits = ParcelFileDescriptor.MODE_READ_ONLY; - originalFile = "file://" + uri.getQueryParameter("file"); - String sessionKey = uri.getQueryParameter("sessionkey"); - // TODO: Check that sessionKey is valid. - - // Decrypt file - // CryptoHelper ch = ServiceDispatchImpl.ch; // Use the global crypto helper that is connected to the single service we have. - - if (ch == null) { - if (debug) Log.d(TAG, "OI Safe currently logged out."); - return null; - } - - if (!sessionKey.equals(ch.getCurrentSessionKey())) { - if (debug) Log.d(TAG, "Session keys do not match! " + sessionKey + " != " + ch.getCurrentSessionKey()); - return null; - } - - if (debug) Log.d(TAG, "Original file path: " + originalFile); - if (CategoryList.isSignedIn()==false) { - Intent frontdoor = new Intent(getContext(), Safe.class); - frontdoor.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getContext().startActivity(frontdoor); - throw new CryptoHelperException("Not logged in."); - } - - if (debug) Log.d(TAG, "Decrypt.."); - Uri newuri = ch.decryptFileWithSessionKeyThroughContentProvider(this.getContext(), Uri.parse(originalFile)); - cryptSession = newuri.getPathSegments().get(1); - sessionFile=SESSION_FILE+"."+cryptSession; - path += "/"+sessionFile; - if (debug) Log.d(TAG, "New path: " + path); - break; - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - - if (debug) Log.d(TAG,"openFile: path="+path); - pfd=ParcelFileDescriptor.open(new File(path), modeBits); - // This is pretty sneaky. After opening the file, - // we'll immediately delete the file. - // Files are not truly deleted if there is an open file - // handle. The file will not be deleted until the - // file handle is closed. And then it magically - // disappears. This makes for a one time use - // content provider. - if (!getContext().deleteFile(sessionFile)) { - if (debug) Log.e(TAG,"openFile: unable to delete: "+sessionFile); - } - } catch (FileNotFoundException e) { - if (debug) Log.d(TAG,"openFile: FileNotFound"); - throw e; - } catch (IllegalArgumentException e) { - throw e; - } catch (CryptoHelperException e) { - if (debug) Log.d(TAG,"openFile: CryptoHelperException:"+e.getLocalizedMessage()); - pfd = null; - //throw e; - } - - return pfd; - } - - @Override - public int update(Uri uri, ContentValues contentvalues, String s, - String[] as) { - // not supported - return 0; - } + return null; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) + throws FileNotFoundException { + if (debug) { + Log.d(TAG, "openFile(" + uri.toString() + "," + mode + ")"); + } + + ParcelFileDescriptor pfd = null; + try { + // get the /files/ directory for our application, which + // for us is /data/data/org.openintents.safe/files/ + String filesDir = getContext().getFilesDir().toString(); + + String path = filesDir; + String cryptSession; + String sessionFile; + String originalFile; + int modeBits = 0; + switch (sUriMatcher.match(uri)) { + case ENCRYPT_ID: + if (debug) { + Log.d(TAG, "openFile: ENCRYPT"); + } + modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY | + ParcelFileDescriptor.MODE_CREATE; + cryptSession = uri.getPathSegments().get(1); + sessionFile = SESSION_FILE + "." + cryptSession; + path += "/" + sessionFile; + break; + case DECRYPT_ID: + if (debug) { + Log.d(TAG, "openFile: DECRYPT"); + } + modeBits = ParcelFileDescriptor.MODE_READ_ONLY; + cryptSession = uri.getPathSegments().get(1); + sessionFile = SESSION_FILE + "." + cryptSession; + path += "/" + sessionFile; + break; + case DECRYPT_FILE_ID: + if (debug) { + Log.d(TAG, "openFile: DECRYPT_FILE"); + } + modeBits = ParcelFileDescriptor.MODE_READ_ONLY; + originalFile = "file://" + uri.getQueryParameter("file"); + String sessionKey = uri.getQueryParameter("sessionkey"); + // TODO: Check that sessionKey is valid. + + // Decrypt file + // CryptoHelper ch = ServiceDispatchImpl.ch; // Use the global crypto helper that is connected to the single service we have. + + if (ch == null) { + if (debug) { + Log.d(TAG, "OI Safe currently logged out."); + } + return null; + } + + if (!sessionKey.equals(ch.getCurrentSessionKey())) { + if (debug) { + Log.d(TAG, "Session keys do not match! " + sessionKey + " != " + ch.getCurrentSessionKey()); + } + return null; + } + + if (debug) { + Log.d(TAG, "Original file path: " + originalFile); + } + if (CategoryList.isSignedIn() == false) { + Intent frontdoor = new Intent(getContext(), Safe.class); + frontdoor.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getContext().startActivity(frontdoor); + throw new CryptoHelperException("Not logged in."); + } + + if (debug) { + Log.d(TAG, "Decrypt.."); + } + Uri newuri = ch.decryptFileWithSessionKeyThroughContentProvider(this.getContext(), Uri.parse(originalFile)); + cryptSession = newuri.getPathSegments().get(1); + sessionFile = SESSION_FILE + "." + cryptSession; + path += "/" + sessionFile; + if (debug) { + Log.d(TAG, "New path: " + path); + } + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + + if (debug) { + Log.d(TAG, "openFile: path=" + path); + } + pfd = ParcelFileDescriptor.open(new File(path), modeBits); + // This is pretty sneaky. After opening the file, + // we'll immediately delete the file. + // Files are not truly deleted if there is an open file + // handle. The file will not be deleted until the + // file handle is closed. And then it magically + // disappears. This makes for a one time use + // content provider. + if (!getContext().deleteFile(sessionFile)) { + if (debug) { + Log.e(TAG, "openFile: unable to delete: " + sessionFile); + } + } + } catch (FileNotFoundException e) { + if (debug) { + Log.d(TAG, "openFile: FileNotFound"); + } + throw e; + } catch (IllegalArgumentException e) { + throw e; + } catch (CryptoHelperException e) { + if (debug) { + Log.d(TAG, "openFile: CryptoHelperException:" + e.getLocalizedMessage()); + } + pfd = null; + //throw e; + } + + return pfd; + } + + @Override + public int update(Uri uri, ContentValues contentvalues, String s, + String[] as) { + // not supported + return 0; + } } diff --git a/Safe/src/org/openintents/safe/CryptoHelper.java b/Safe/src/org/openintents/safe/CryptoHelper.java index 71f7dbea..d1c37c9b 100644 --- a/Safe/src/org/openintents/safe/CryptoHelper.java +++ b/Safe/src/org/openintents/safe/CryptoHelper.java @@ -15,6 +15,21 @@ */ package org.openintents.safe; +import android.content.ContentResolver; +import android.content.Context; +import android.net.Uri; +import android.os.Environment; +import android.util.Log; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; @@ -31,32 +46,17 @@ import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.KeyGenerator; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - import org.openintents.util.SecureDelete; -import android.content.ContentResolver; -import android.content.Context; -import android.net.Uri; -import android.os.Environment; -import android.util.Log; import estreamj.ciphers.trivium.Trivium; import estreamj.framework.ESJException; /** * Crypto helper class. - * + *

* Basic crypto class that uses Bouncy Castle Provider to * encrypt/decrypt data using PBE (Password Based Encryption) via - * 128Bit AES. I'm fairly new to both Crypto and Java so if you + * 128Bit AES. I'm fairly new to both Crypto and Java so if you * notice I've done something terribly wrong here please let me * know. * @@ -64,959 +64,1004 @@ */ public class CryptoHelper { - private static final boolean debug = false; - private static String TAG = "CryptoHelper"; + private static final boolean debug = false; + private static String TAG = "CryptoHelper"; - public static final String OISAFE_EXTENSION = ".oisafe"; + public static final String OISAFE_EXTENSION = ".oisafe"; - protected static PBEKeySpec pbeKeySpec; - protected static PBEParameterSpec pbeParamSpec; - protected static SecretKeyFactory keyFac; + protected static PBEKeySpec pbeKeySpec; + protected static PBEParameterSpec pbeParamSpec; + protected static SecretKeyFactory keyFac; - public final static int EncryptionMedium=1; - public final static int EncryptionStrong=2; + public final static int EncryptionMedium = 1; + public final static int EncryptionStrong = 2; - protected static String algorithmMedium = "PBEWithMD5And128BitAES-CBC-OpenSSL"; -// protected static String algorithm = "PBEWithSHA1And128BitAES-CBC-BC"; // slower - protected static String algorithmStrong = "PBEWithSHA1And256BitAES-CBC-BC"; - private String algorithm = ""; - protected static String desAlgorithm = "DES"; - protected static String password = null; - protected static SecretKey pbeKey; - protected static Cipher pbeCipher; - private boolean status=false; // status of the last encrypt/decrypt + protected static String algorithmMedium = "PBEWithMD5And128BitAES-CBC-OpenSSL"; + // protected static String algorithm = "PBEWithSHA1And128BitAES-CBC-BC"; // slower + protected static String algorithmStrong = "PBEWithSHA1And256BitAES-CBC-BC"; + private String algorithm = ""; + protected static String desAlgorithm = "DES"; + protected static String password = null; + protected static SecretKey pbeKey; + protected static Cipher pbeCipher; + private boolean status = false; // status of the last encrypt/decrypt - private static byte[] salt = null; + private static byte[] salt = null; - private static final int count = 20; + private static final int count = 20; - /** - * Session key for content provider. - */ - private String sessionKey = null; + /** + * Session key for content provider. + */ + private String sessionKey = null; - - /** - * Constructor which defaults to a medium encryption level. - */ - public CryptoHelper() { + /** + * Constructor which defaults to a medium encryption level. + */ + public CryptoHelper() { // initialize(EncryptionMedium); - } - /** - * Constructor which allows the specification of the encryption level. - * - * @param strength encryption strength - * @param salt salt to be used - */ - public void init(int strength, String salt) throws CryptoHelperException { - try { - setSalt(salt); - initialize(strength); - } catch (CryptoHelperException e) { - e.printStackTrace(); - throw e; - } - } - /** - * Initialize the class. Sets the encryption level for the instance - * and generates the secret key factory. - * - * @param Strength - */ - private void initialize(int Strength) { - switch (Strength) { - case EncryptionMedium: - algorithm=algorithmMedium; - break; - case EncryptionStrong: - algorithm=algorithmStrong; - break; - } - pbeParamSpec = new PBEParameterSpec(salt,count); - try { - keyFac = SecretKeyFactory - .getInstance(algorithm,"BC"); - } catch (NoSuchAlgorithmException e) { - Log.e(TAG,"CryptoHelper(): "+e.toString()); - } catch (NoSuchProviderException e) { - Log.e(TAG,"CryptoHelper(): "+e.toString()); - } - } - - /** - * Generate a random salt for use with the cipher. - * - * @author Randy McEoin - * @return String version of the 8 byte salt - */ - public static String generateSalt() throws NoSuchAlgorithmException { - byte[] salt = new byte[8]; - SecureRandom sr; - try { - sr = SecureRandom.getInstance("SHA1PRNG"); - sr.nextBytes(salt); - if (debug) Log.d(TAG,"generateSalt: salt="+salt.toString()); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - throw e; - } - return toHexString(salt); - } - /** - * @author Isaac Potoczny-Jones - * - * @return null if failure, otherwise hex string version of key - */ - public static String generateMasterKey () throws NoSuchAlgorithmException { - try { - KeyGenerator keygen; - keygen = KeyGenerator.getInstance("AES"); - keygen.init(256); - SecretKey genDesKey = keygen.generateKey(); - return toHexString(genDesKey.getEncoded()); - } catch (NoSuchAlgorithmException e) { - Log.e(TAG,"generateMasterKey(): "+e.toString()); - throw e; - } - } - - /** - * - * @param message - * @return MD5 digest of message in a byte array - * @throws NoSuchAlgorithmException - * @throws IOException - */ - public static byte[] md5String(String message) { - - byte[] input = message.getBytes(); - - MessageDigest hash; - ByteArrayInputStream bIn = null; - DigestInputStream dIn = null; - - try { - hash = MessageDigest.getInstance("MD5"); - - bIn = new ByteArrayInputStream(input); - dIn = new DigestInputStream(bIn, hash); - - for(int i=0;i= 0) { - tri.process(bytesIn, 0, - bytesOut, 0, numRead); - - os.write(bytesOut, 0, numRead); - offset += numRead; - } - - // Ensure all the bytes have been read in - if (offset < is.available()) { - throw new IOException("Could not completely read file "); - } - - // Close the input stream and return bytes - is.close(); - os.close(); - - // Securely delete the original file: - SecureDelete.delete(new File(fileUri.getPath())); - status=true; - - } catch (ESJException e) { - Log.e(TAG, "Error encrypting file", e); - } - } catch (FileNotFoundException e) { - Log.e(TAG, "File not found", e); - } catch (IOException e) { - Log.e(TAG, "IO Exception", e); - } - - if (status==false) { - return null; - } - return Uri.fromFile(new File(outputPath)); //Uri.parse("file://" + outputPath); // TODO: UUEncode - } - /** - * @return - */ - private String getTemporaryFileName() throws CryptoHelperException { - String randomPart; - try { - // create a random session name - randomPart=generateSalt(); - } catch (NoSuchAlgorithmException e1) { - e1.printStackTrace(); - String msg = "Decrypt error: "+e1.getLocalizedMessage(); - throw new CryptoHelperException(msg); - } - - return Environment - .getExternalStorageDirectory().toString() + "/tmp-" + randomPart; - } - - /** - * Dencrypt a file previously encrypted with - * encryptFileWithSessionKey(). - * - * Creates a new file without the .oisafe extension. - * - * @author Peli - * - * @param ctx Context of activity in order to store temp file - * @param fileUri Uri to either a stream or a file to read from - * @return If decryption is successful, returns Uri of a content - * provider to read the plaintext file. Upon failure, - * return null. - * @throws Exception - */ - public Uri decryptFileWithSessionKey(Context ctx, Uri fileUri) throws CryptoHelperException { - if (debug) Log.d(TAG, "fileUri="+fileUri.toString()); - ContentResolver contentResolver = ctx.getContentResolver(); - - String inputPath = null; - String outputPath = null; - Uri resultUri = null; - boolean result = false; - - try { - InputStream is; - if (fileUri.getScheme().equals("file")) { - inputPath = fileUri.getPath(); - is = new java.io.FileInputStream(inputPath); - if (debug) Log.d(TAG, "Decrypt: Input from " + inputPath); - if (inputPath.endsWith(OISAFE_EXTENSION)) { - outputPath = inputPath.substring(0, inputPath.length() - OISAFE_EXTENSION.length()); - } - } else { - is = contentResolver.openInputStream(fileUri); - if (debug) Log.d(TAG, "Decrypt: Input from " + fileUri.toString()); - } - - if (outputPath == null) { - outputPath = getTemporaryFileName(); - } - - FileOutputStream os = new FileOutputStream(outputPath); - - // after writing the decrypted content to a temporary file, - // pass back a Uri that can be used to read back the contents - resultUri = Uri.fromFile(new File(outputPath)); //Uri.parse("file://" + outputPath); // TODO: UUEncode? - - result = decryptStreamWithSessionKey(ctx, is, os); - - // Close the input stream - is.close(); - os.close(); - - } catch (FileNotFoundException e) { - Log.e(TAG, "File not found", e); - } catch (IOException e) { - Log.e(TAG, "IOException", e); - } catch (IllegalArgumentException e) { - Log.e(TAG, "IllegalArgumentException", e); - } - - - if (result == true) { - // Successful - - // Securely delete the original file: - if (inputPath != null) { - SecureDelete.delete(new File(inputPath)); - } - } else { - resultUri = null; - - // Unsuccessful. Clean up - //ctx.deleteFile(sessionFile); - } - - return resultUri; - } - - /** - * Dencrypt a file previously encrypted with - * encryptFileWithSessionKey(). - * - * The original file is not modified - * - * @author Peli - * - * @param ctx Context of activity in order to store temp file - * @param fileUri Uri to either a stream or a file to read from - * @return If decryption is successful, returns Uri of a content - * provider to read the plaintext file. Upon failure, - * return null. - * @throws Exception - */ - public Uri decryptFileWithSessionKeyThroughContentProvider(Context ctx, Uri fileUri) throws CryptoHelperException { - if (debug) Log.d(TAG, "fileUri="+fileUri.toString()); - ContentResolver contentResolver = ctx.getContentResolver(); - - String sessionFile = ""; - Uri resultUri = null; - boolean result = false; - - try { - InputStream is; - if (fileUri.getScheme().equals("file")) { - is = new java.io.FileInputStream(fileUri.getPath()); - if (debug) Log.d(TAG, "Decrypt: Input from " + fileUri.getPath()); - } else { - is = contentResolver.openInputStream(fileUri); - if (debug) Log.d(TAG, "Decrypt: Input from " + fileUri.toString()); - } - FileOutputStream os = null; - - String decryptSession; - try { - // create a random session name - decryptSession=generateSalt(); - } catch (NoSuchAlgorithmException e1) { - e1.printStackTrace(); - String msg = "Decrypt error: "+e1.getLocalizedMessage(); - throw new CryptoHelperException(msg); - } - sessionFile = CryptoContentProvider.SESSION_FILE+"."+decryptSession; - if (debug) Log.d(TAG, "Decrypt: Output to " + sessionFile); - - // openFileOutput creates a file in /data/data/{packagename}/files/ - // In our case, /data/data/org.openintents.safe/files/ - // This file is owned and only readable by our application - os = ctx.openFileOutput(sessionFile, - Context.MODE_PRIVATE); - - // after writing the decrypted content to a temporary file, - // pass back a Uri that can be used to read back the contents - resultUri = Uri.withAppendedPath(CryptoContentProvider.CONTENT_URI, "decrypt/" + decryptSession); - - result = decryptStreamWithSessionKey(ctx, is, os); - - // Close the input stream - is.close(); - os.close(); - - } catch (FileNotFoundException e) { - Log.e(TAG, "File not found", e); - } catch (IOException e) { - Log.e(TAG, "IOException", e); - } - - if (result == false) { - resultUri = null; - - // Unsuccessful. Clean up - ctx.deleteFile(sessionFile); - } - - return resultUri; - } - - /** - * Unencrypt a file previously encrypted with - * encryptFileWithSessionKey(). - * - * @author Peli - * - * @param ctx Context of activity in order to store temp file - * @param fileUri Uri to either a stream or a file to read from - * @param useContentProvider true for using Content Provider, - * false for creating a file without ".oisafe" extension and - * deleting the original file. - * @return True if successful, otherwise false. - * @throws Exception - */ - public boolean decryptStreamWithSessionKey(Context ctx, InputStream is, OutputStream os) throws CryptoHelperException { - if (debug) Log.d(TAG, "decryptStreamWithSessionKey"); - status=false; // assume failure - if(password == null) { - String msg = "Must call setPassword before running decrypt."; - throw new CryptoHelperException(msg); - } - - try { - - int numReadTotal = 0; - int numRead = 0; - - byte[] byteCipherVersion = new byte[1]; - while ((numRead = is.read(byteCipherVersion, numRead, - byteCipherVersion.length - numRead)) >= 0 - && numReadTotal < byteCipherVersion.length) { - if (debug) Log.d(TAG, "read bytes: " + numRead); - numReadTotal += numRead; - } - String cipherVersion = new String(byteCipherVersion); - - byte[] byteCipherSessionKey = null; - - // Split cipher into session key and text - try { - if (debug) Log.d(TAG, "cipherVersion : " + cipherVersion); - if (cipherVersion.equals("A")) { - - numRead = 0; - numReadTotal = 0; - byteCipherSessionKey = new byte[48]; - // Read the first few bytes that contain the encrypted key - while ((numRead = is.read(byteCipherSessionKey, numRead, - byteCipherSessionKey.length - numRead)) >= 0 - && numReadTotal < byteCipherSessionKey.length) { - if (debug) Log.d(TAG, "read bytes sessionKey: " + numRead); - numReadTotal += numRead; - } - } else { - Log.e(TAG, "Unknown cipher version" + cipherVersion); - return false; - } - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Invalid ciphertext (with session key)"); - return false; - } - - // Decrypt the session key - byte[] byteSessionKey = {}; - - try { - pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec); - byteSessionKey = pbeCipher.doFinal(byteCipherSessionKey); - status=true; - } catch (IllegalBlockSizeException e) { - Log.e(TAG,"decrypt(): "+e.toString()); - } catch (BadPaddingException e) { - Log.e(TAG,"decrypt(): "+e.toString()); - } catch (InvalidKeyException e) { - Log.e(TAG,"decrypt(): "+e.toString()); - } catch (InvalidAlgorithmParameterException e) { - Log.e(TAG,"decrypt(): "+e.toString()); - } - - // Now decrypt the message - Trivium tri = new Trivium(); - try { - tri.setupKey(Trivium.MODE_DECRYPT, - byteSessionKey, 0); - tri.setupNonce(byteSessionKey, 10); - - // Create the byte array to hold the data - final int bytesLen = 4096; // buffer length - byte[] bytesIn = new byte[bytesLen]; - byte[] bytesOut = new byte[bytesLen]; - - int offset = 0; - numRead = 0; - while ((numRead = is.read(bytesIn, 0, bytesLen)) >= 0) { - tri.process(bytesIn, 0, - bytesOut, 0, numRead); - - os.write(bytesOut, 0, numRead); - offset += numRead; - } - - // Ensure all the bytes have been read in - if (offset < is.available()) { - throw new IOException("Could not completely read file "); - } - status=true; - - } catch (ESJException e) { - Log.e(TAG, "Error decrypting file", e); - } - - } catch (IOException e) { - Log.e(TAG, "IOException", e); - } - - return status; - } + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "generateMasterKey(): " + e.toString()); + return null; + } + + // Encrypt the session key using the master key + try { + pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec); + cipherSessionKey = pbeCipher.doFinal(sessionKeyEncoded); + status = true; + } catch (IllegalBlockSizeException e) { + Log.e(TAG, "encryptWithSessionKey(): " + e.toString()); + } catch (BadPaddingException e) { + Log.e(TAG, "encryptWithSessionKey(): " + e.toString()); + } catch (InvalidKeyException e) { + Log.e(TAG, "encryptWithSessionKey(): " + e.toString()); + } catch (InvalidAlgorithmParameterException e) { + Log.e(TAG, "encryptWithSessionKey(): " + e.toString()); + } + if (status == false) { + return null; + } + status = false; + + String stringCipherVersion = "A"; + byte[] bytesCipherVersion = stringCipherVersion.getBytes(); + os.write(bytesCipherVersion, 0, bytesCipherVersion.length); + + os.write(cipherSessionKey, 0, cipherSessionKey.length); + + if (debug) { + Log.d(TAG, "bytesCipherVersion.length: " + bytesCipherVersion.length); + } + if (debug) { + Log.d(TAG, "cipherSessionKey.length: " + cipherSessionKey.length); + } + + Trivium tri = new Trivium(); + try { + tri.setupKey( + Trivium.MODE_ENCRYPT, + sessionKeyEncoded, 0 + ); + tri.setupNonce(sessionKeyEncoded, 10); + + // Create the byte array to hold the data + final int bytesLen = 4096; // buffer length + byte[] bytesIn = new byte[bytesLen]; + byte[] bytesOut = new byte[bytesLen]; + + int offset = 0; + int numRead = 0; + while ((numRead = is.read(bytesIn, 0, bytesLen)) >= 0) { + tri.process( + bytesIn, 0, + bytesOut, 0, numRead + ); + + os.write(bytesOut, 0, numRead); + offset += numRead; + } + + // Ensure all the bytes have been read in + if (offset < is.available()) { + throw new IOException("Could not completely read file "); + } + + // Close the input stream and return bytes + is.close(); + os.close(); + + // Securely delete the original file: + SecureDelete.delete(new File(fileUri.getPath())); + status = true; + + } catch (ESJException e) { + Log.e(TAG, "Error encrypting file", e); + } + } catch (FileNotFoundException e) { + Log.e(TAG, "File not found", e); + } catch (IOException e) { + Log.e(TAG, "IO Exception", e); + } + + if (status == false) { + return null; + } + return Uri.fromFile(new File(outputPath)); //Uri.parse("file://" + outputPath); // TODO: UUEncode + } + + /** + * @return + */ + private String getTemporaryFileName() throws CryptoHelperException { + String randomPart; + try { + // create a random session name + randomPart = generateSalt(); + } catch (NoSuchAlgorithmException e1) { + e1.printStackTrace(); + String msg = "Decrypt error: " + e1.getLocalizedMessage(); + throw new CryptoHelperException(msg); + } + + return Environment + .getExternalStorageDirectory().toString() + "/tmp-" + randomPart; + } + + /** + * Dencrypt a file previously encrypted with + * encryptFileWithSessionKey(). + *

+ * Creates a new file without the .oisafe extension. + * + * @param ctx Context of activity in order to store temp file + * @param fileUri Uri to either a stream or a file to read from + * @return If decryption is successful, returns Uri of a content + * provider to read the plaintext file. Upon failure, + * return null. + * @throws Exception + * @author Peli + */ + public Uri decryptFileWithSessionKey(Context ctx, Uri fileUri) throws CryptoHelperException { + if (debug) { + Log.d(TAG, "fileUri=" + fileUri.toString()); + } + ContentResolver contentResolver = ctx.getContentResolver(); + + String inputPath = null; + String outputPath = null; + Uri resultUri = null; + boolean result = false; + + try { + InputStream is; + if (fileUri.getScheme().equals("file")) { + inputPath = fileUri.getPath(); + is = new java.io.FileInputStream(inputPath); + if (debug) { + Log.d(TAG, "Decrypt: Input from " + inputPath); + } + if (inputPath.endsWith(OISAFE_EXTENSION)) { + outputPath = inputPath.substring(0, inputPath.length() - OISAFE_EXTENSION.length()); + } + } else { + is = contentResolver.openInputStream(fileUri); + if (debug) { + Log.d(TAG, "Decrypt: Input from " + fileUri.toString()); + } + } + + if (outputPath == null) { + outputPath = getTemporaryFileName(); + } + + FileOutputStream os = new FileOutputStream(outputPath); + + // after writing the decrypted content to a temporary file, + // pass back a Uri that can be used to read back the contents + resultUri = Uri.fromFile(new File(outputPath)); //Uri.parse("file://" + outputPath); // TODO: UUEncode? + + result = decryptStreamWithSessionKey(ctx, is, os); + + // Close the input stream + is.close(); + os.close(); + + } catch (FileNotFoundException e) { + Log.e(TAG, "File not found", e); + } catch (IOException e) { + Log.e(TAG, "IOException", e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "IllegalArgumentException", e); + } + + if (result == true) { + // Successful + + // Securely delete the original file: + if (inputPath != null) { + SecureDelete.delete(new File(inputPath)); + } + } else { + resultUri = null; + + // Unsuccessful. Clean up + //ctx.deleteFile(sessionFile); + } + + return resultUri; + } + + /** + * Dencrypt a file previously encrypted with + * encryptFileWithSessionKey(). + *

+ * The original file is not modified + * + * @param ctx Context of activity in order to store temp file + * @param fileUri Uri to either a stream or a file to read from + * @return If decryption is successful, returns Uri of a content + * provider to read the plaintext file. Upon failure, + * return null. + * @throws Exception + * @author Peli + */ + public Uri decryptFileWithSessionKeyThroughContentProvider(Context ctx, Uri fileUri) throws CryptoHelperException { + if (debug) { + Log.d(TAG, "fileUri=" + fileUri.toString()); + } + ContentResolver contentResolver = ctx.getContentResolver(); + + String sessionFile = ""; + Uri resultUri = null; + boolean result = false; + + try { + InputStream is; + if (fileUri.getScheme().equals("file")) { + is = new java.io.FileInputStream(fileUri.getPath()); + if (debug) { + Log.d(TAG, "Decrypt: Input from " + fileUri.getPath()); + } + } else { + is = contentResolver.openInputStream(fileUri); + if (debug) { + Log.d(TAG, "Decrypt: Input from " + fileUri.toString()); + } + } + FileOutputStream os = null; + + String decryptSession; + try { + // create a random session name + decryptSession = generateSalt(); + } catch (NoSuchAlgorithmException e1) { + e1.printStackTrace(); + String msg = "Decrypt error: " + e1.getLocalizedMessage(); + throw new CryptoHelperException(msg); + } + sessionFile = CryptoContentProvider.SESSION_FILE + "." + decryptSession; + if (debug) { + Log.d(TAG, "Decrypt: Output to " + sessionFile); + } + + // openFileOutput creates a file in /data/data/{packagename}/files/ + // In our case, /data/data/org.openintents.safe/files/ + // This file is owned and only readable by our application + os = ctx.openFileOutput( + sessionFile, + Context.MODE_PRIVATE + ); + + // after writing the decrypted content to a temporary file, + // pass back a Uri that can be used to read back the contents + resultUri = Uri.withAppendedPath(CryptoContentProvider.CONTENT_URI, "decrypt/" + decryptSession); + + result = decryptStreamWithSessionKey(ctx, is, os); + + // Close the input stream + is.close(); + os.close(); + + } catch (FileNotFoundException e) { + Log.e(TAG, "File not found", e); + } catch (IOException e) { + Log.e(TAG, "IOException", e); + } + + if (result == false) { + resultUri = null; + + // Unsuccessful. Clean up + ctx.deleteFile(sessionFile); + } + + return resultUri; + } + + /** + * Unencrypt a file previously encrypted with + * encryptFileWithSessionKey(). + * + * @param ctx Context of activity in order to store temp file + * @param fileUri Uri to either a stream or a file to read from + * @param useContentProvider true for using Content Provider, + * false for creating a file without ".oisafe" extension and + * deleting the original file. + * @return True if successful, otherwise false. + * @throws Exception + * @author Peli + */ + public boolean decryptStreamWithSessionKey(Context ctx, InputStream is, OutputStream os) throws CryptoHelperException { + if (debug) { + Log.d(TAG, "decryptStreamWithSessionKey"); + } + status = false; // assume failure + if (password == null) { + String msg = "Must call setPassword before running decrypt."; + throw new CryptoHelperException(msg); + } + + try { + + int numReadTotal = 0; + int numRead = 0; + + byte[] byteCipherVersion = new byte[1]; + while ((numRead = is.read( + byteCipherVersion, numRead, + byteCipherVersion.length - numRead + )) >= 0 + && numReadTotal < byteCipherVersion.length) { + if (debug) { + Log.d(TAG, "read bytes: " + numRead); + } + numReadTotal += numRead; + } + String cipherVersion = new String(byteCipherVersion); + + byte[] byteCipherSessionKey = null; + + // Split cipher into session key and text + try { + if (debug) { + Log.d(TAG, "cipherVersion : " + cipherVersion); + } + if (cipherVersion.equals("A")) { + + numRead = 0; + numReadTotal = 0; + byteCipherSessionKey = new byte[48]; + // Read the first few bytes that contain the encrypted key + while ((numRead = is.read( + byteCipherSessionKey, numRead, + byteCipherSessionKey.length - numRead + )) >= 0 + && numReadTotal < byteCipherSessionKey.length) { + if (debug) { + Log.d(TAG, "read bytes sessionKey: " + numRead); + } + numReadTotal += numRead; + } + } else { + Log.e(TAG, "Unknown cipher version" + cipherVersion); + return false; + } + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Invalid ciphertext (with session key)"); + return false; + } + + // Decrypt the session key + byte[] byteSessionKey = {}; + + try { + pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec); + byteSessionKey = pbeCipher.doFinal(byteCipherSessionKey); + status = true; + } catch (IllegalBlockSizeException e) { + Log.e(TAG, "decrypt(): " + e.toString()); + } catch (BadPaddingException e) { + Log.e(TAG, "decrypt(): " + e.toString()); + } catch (InvalidKeyException e) { + Log.e(TAG, "decrypt(): " + e.toString()); + } catch (InvalidAlgorithmParameterException e) { + Log.e(TAG, "decrypt(): " + e.toString()); + } + + // Now decrypt the message + Trivium tri = new Trivium(); + try { + tri.setupKey( + Trivium.MODE_DECRYPT, + byteSessionKey, 0 + ); + tri.setupNonce(byteSessionKey, 10); + + // Create the byte array to hold the data + final int bytesLen = 4096; // buffer length + byte[] bytesIn = new byte[bytesLen]; + byte[] bytesOut = new byte[bytesLen]; + + int offset = 0; + numRead = 0; + while ((numRead = is.read(bytesIn, 0, bytesLen)) >= 0) { + tri.process( + bytesIn, 0, + bytesOut, 0, numRead + ); + + os.write(bytesOut, 0, numRead); + offset += numRead; + } + + // Ensure all the bytes have been read in + if (offset < is.available()) { + throw new IOException("Could not completely read file "); + } + status = true; + + } catch (ESJException e) { + Log.e(TAG, "Error decrypting file", e); + } + + } catch (IOException e) { + Log.e(TAG, "IOException", e); + } + + return status; + } } diff --git a/Safe/src/org/openintents/safe/CryptoHelperException.java b/Safe/src/org/openintents/safe/CryptoHelperException.java index 5c601811..832d1d90 100644 --- a/Safe/src/org/openintents/safe/CryptoHelperException.java +++ b/Safe/src/org/openintents/safe/CryptoHelperException.java @@ -21,10 +21,10 @@ */ public class CryptoHelperException extends Exception { - private static final long serialVersionUID = 9198874648607918125L; + private static final long serialVersionUID = 9198874648607918125L; - public CryptoHelperException(String message) { - super(message); - } + public CryptoHelperException(String message) { + super(message); + } -} \ No newline at end of file +} diff --git a/Safe/src/org/openintents/safe/DBHelper.java b/Safe/src/org/openintents/safe/DBHelper.java index d49ca8d4..6a71ecdb 100644 --- a/Safe/src/org/openintents/safe/DBHelper.java +++ b/Safe/src/org/openintents/safe/DBHelper.java @@ -16,12 +16,6 @@ */ package org.openintents.safe; -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; - import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -30,855 +24,871 @@ import android.database.sqlite.SQLiteDiskIOException; import android.util.Log; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + /** - * DBHelper class. - * + * DBHelper class. + *

* The overall theme of this class was borrowed from the Notepad * example Open Handset Alliance website. It's essentially a very * primitive database layer. - * + * * @author Steven Osborn - http://steven.bitsetters.com */ public class DBHelper { - private static final boolean debug = false; - - private static final String DATABASE_NAME = "safe"; - private static final String TABLE_DBVERSION = "dbversion"; - private static final String TABLE_PASSWORDS = "passwords"; - private static final String TABLE_CATEGORIES = "categories"; - private static final String TABLE_MASTER_KEY = "master_key"; - private static final String TABLE_SALT = "salt"; - private static final String TABLE_PACKAGE_ACCESS = "package_access"; - private static final String TABLE_CIPHER_ACCESS = "cipher_access"; - private static final int DATABASE_VERSION = 4; - private static String TAG = "DBHelper"; - Context myCtx; - - private static final String DBVERSION_CREATE = - "create table " + TABLE_DBVERSION + " (" - + "version integer not null);"; - - private static final String PASSWORDS_CREATE = - "create table " + TABLE_PASSWORDS + " (" - + "id integer primary key autoincrement, " - + "category integer not null, " - + "password text not null, " - + "description text not null, " - + "username text, " - + "website text, " - + "note text, " - + "unique_name text, " //might be null - + "lastdatetimeedit text);"; - - private static final String PASSWORDS_DROP = - "drop table " + TABLE_PASSWORDS + ";"; - - private static final String PACKAGE_ACCESS_CREATE = - "create table " + TABLE_PACKAGE_ACCESS + " (" - + "id integer not null, " - + "package text not null);"; - - private static final String PACKAGE_ACCESS_DROP = - "drop table " + TABLE_PACKAGE_ACCESS + ";"; - - private static final String CATEGORIES_CREATE = - "create table " + TABLE_CATEGORIES + " (" - + "id integer primary key autoincrement, " - + "name text not null, " - + "lastdatetimeedit text);"; - - private static final String CATEGORIES_DROP = - "drop table " + TABLE_CATEGORIES + ";"; - - private static final String MASTER_KEY_CREATE = - "create table " + TABLE_MASTER_KEY + " (" - + "encryptedkey text not null);"; - - private static final String SALT_CREATE = - "create table " + TABLE_SALT + " (" - + "salt text not null);"; - - private static final String CIPHER_ACCESS_CREATE = - "create table " + TABLE_CIPHER_ACCESS + " (" - + "id integer primary key autoincrement, " - + "packagename text not null, " - + "expires integer not null, " - + "dateadded text not null);"; + private static final boolean debug = false; + + private static final String DATABASE_NAME = "safe"; + private static final String TABLE_DBVERSION = "dbversion"; + private static final String TABLE_PASSWORDS = "passwords"; + private static final String TABLE_CATEGORIES = "categories"; + private static final String TABLE_MASTER_KEY = "master_key"; + private static final String TABLE_SALT = "salt"; + private static final String TABLE_PACKAGE_ACCESS = "package_access"; + private static final String TABLE_CIPHER_ACCESS = "cipher_access"; + private static final int DATABASE_VERSION = 4; + private static String TAG = "DBHelper"; + Context myCtx; + + private static final String DBVERSION_CREATE = + "create table " + TABLE_DBVERSION + " (" + + "version integer not null);"; + + private static final String PASSWORDS_CREATE = + "create table " + TABLE_PASSWORDS + " (" + + "id integer primary key autoincrement, " + + "category integer not null, " + + "password text not null, " + + "description text not null, " + + "username text, " + + "website text, " + + "note text, " + + "unique_name text, " //might be null + + "lastdatetimeedit text);"; + + private static final String PASSWORDS_DROP = + "drop table " + TABLE_PASSWORDS + ";"; + + private static final String PACKAGE_ACCESS_CREATE = + "create table " + TABLE_PACKAGE_ACCESS + " (" + + "id integer not null, " + + "package text not null);"; + + private static final String PACKAGE_ACCESS_DROP = + "drop table " + TABLE_PACKAGE_ACCESS + ";"; + + private static final String CATEGORIES_CREATE = + "create table " + TABLE_CATEGORIES + " (" + + "id integer primary key autoincrement, " + + "name text not null, " + + "lastdatetimeedit text);"; + + private static final String CATEGORIES_DROP = + "drop table " + TABLE_CATEGORIES + ";"; + + private static final String MASTER_KEY_CREATE = + "create table " + TABLE_MASTER_KEY + " (" + + "encryptedkey text not null);"; + + private static final String SALT_CREATE = + "create table " + TABLE_SALT + " (" + + "salt text not null);"; + + private static final String CIPHER_ACCESS_CREATE = + "create table " + TABLE_CIPHER_ACCESS + " (" + + "id integer primary key autoincrement, " + + "packagename text not null, " + + "expires integer not null, " + + "dateadded text not null);"; // private static final String CIPHER_ACCESS_DROP = // "drop table " + TABLE_CIPHER_ACCESS + ";"; - private SQLiteDatabase db=null; - private static boolean needsPrePopulation=false; - private static boolean needsUpgrade=false; - - /** - * - * @param ctx - */ - public DBHelper(Context ctx) { - myCtx = ctx; - try { - db = myCtx.openOrCreateDatabase(DATABASE_NAME, 0,null); - - // avoid journals in the file system as it gives access to the passwords. - // FIXME: if you can get hold of a memory dump you could still get access to the passwords. - db.rawQuery("PRAGMA journal_mode=MEMORY",null); - - // Check for the existence of the DBVERSION table - // If it doesn't exist than create the overall data, - // otherwise double check the version - Cursor c = - db.query("sqlite_master", new String[] { "name" }, - "type='table' and name='"+TABLE_DBVERSION+"'", null, null, null, null); - int numRows = c.getCount(); - if (numRows < 1) { - CreateDatabase(db); - } else { - int version=0; - Cursor vc = db.query(true, TABLE_DBVERSION, new String[] {"version"}, - null, null, null, null, null,null); - if(vc.getCount() > 0) { - vc.moveToFirst(); - version=vc.getInt(0); - } - vc.close(); - if (version!=DATABASE_VERSION) { - needsUpgrade=true; - Log.e(TAG,"database version mismatch"); - } - } - c.close(); - - }catch (SQLiteDiskIOException e) - { - Log.d(TAG,"SQLite DiskIO exception: " + e.getLocalizedMessage()); - if (debug) Log.d(TAG,"SQLite DiskIO exception: db=" + db); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - public boolean isDatabaseOpen() - { - boolean isOpen=(db!=null); - if (debug) Log.d(TAG,"isDatabaseOpen=="+isOpen); - return (db!=null); - } - - private void CreateDatabase(SQLiteDatabase db) - { - try { - db.execSQL(DBVERSION_CREATE); - ContentValues args = new ContentValues(); - args.put("version", DATABASE_VERSION); - db.insert(TABLE_DBVERSION, null, args); - - db.execSQL(CATEGORIES_CREATE); - needsPrePopulation=true; - - db.execSQL(PASSWORDS_CREATE); - db.execSQL(PACKAGE_ACCESS_CREATE); - db.execSQL(CIPHER_ACCESS_CREATE); - db.execSQL(MASTER_KEY_CREATE); - db.execSQL(SALT_CREATE); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - public void deleteDatabase() - { - try { - db.execSQL(PASSWORDS_DROP); - db.execSQL(PASSWORDS_CREATE); - - db.execSQL(CATEGORIES_DROP); - db.execSQL(CATEGORIES_CREATE); - - db.execSQL(PACKAGE_ACCESS_DROP); - db.execSQL(PACKAGE_ACCESS_CREATE); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - public boolean needsUpgrade() - { - return needsUpgrade; - } - - public boolean getPrePopulate() - { - return needsPrePopulation; - } - - public void clearPrePopulate() - { - needsPrePopulation=false; - } - /** - * Close database connection - */ - public void close() { - if (db==null) return; - try { - db.close(); - } catch (SQLException e) - { - Log.d(TAG,"close exception: " + e.getLocalizedMessage()); - } - } - - public int fetchVersion() { - int version=0; - try { - Cursor c = db.query(true, TABLE_DBVERSION, - new String[] {"version"}, - null, null, null, null, null,null); - if(c.getCount() > 0) { - c.moveToFirst(); - version=c.getInt(0); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return version; - } + private SQLiteDatabase db = null; + private static boolean needsPrePopulation = false; + private static boolean needsUpgrade = false; + + /** + * @param ctx + */ + public DBHelper(Context ctx) { + myCtx = ctx; + try { + db = myCtx.openOrCreateDatabase(DATABASE_NAME, 0, null); + + // avoid journals in the file system as it gives access to the passwords. + // FIXME: if you can get hold of a memory dump you could still get access to the passwords. + db.rawQuery("PRAGMA journal_mode=MEMORY", null); + + // Check for the existence of the DBVERSION table + // If it doesn't exist than create the overall data, + // otherwise double check the version + Cursor c = + db.query( + "sqlite_master", new String[]{"name"}, + "type='table' and name='" + TABLE_DBVERSION + "'", null, null, null, null + ); + int numRows = c.getCount(); + if (numRows < 1) { + CreateDatabase(db); + } else { + int version = 0; + Cursor vc = db.query( + true, TABLE_DBVERSION, new String[]{"version"}, + null, null, null, null, null, null + ); + if (vc.getCount() > 0) { + vc.moveToFirst(); + version = vc.getInt(0); + } + vc.close(); + if (version != DATABASE_VERSION) { + needsUpgrade = true; + Log.e(TAG, "database version mismatch"); + } + } + c.close(); + + } catch (SQLiteDiskIOException e) { + Log.d(TAG, "SQLite DiskIO exception: " + e.getLocalizedMessage()); + if (debug) { + Log.d(TAG, "SQLite DiskIO exception: db=" + db); + } + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + public boolean isDatabaseOpen() { + boolean isOpen = (db != null); + if (debug) { + Log.d(TAG, "isDatabaseOpen==" + isOpen); + } + return (db != null); + } + + private void CreateDatabase(SQLiteDatabase db) { + try { + db.execSQL(DBVERSION_CREATE); + ContentValues args = new ContentValues(); + args.put("version", DATABASE_VERSION); + db.insert(TABLE_DBVERSION, null, args); + + db.execSQL(CATEGORIES_CREATE); + needsPrePopulation = true; + + db.execSQL(PASSWORDS_CREATE); + db.execSQL(PACKAGE_ACCESS_CREATE); + db.execSQL(CIPHER_ACCESS_CREATE); + db.execSQL(MASTER_KEY_CREATE); + db.execSQL(SALT_CREATE); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + public void deleteDatabase() { + try { + db.execSQL(PASSWORDS_DROP); + db.execSQL(PASSWORDS_CREATE); + + db.execSQL(CATEGORIES_DROP); + db.execSQL(CATEGORIES_CREATE); + + db.execSQL(PACKAGE_ACCESS_DROP); + db.execSQL(PACKAGE_ACCESS_CREATE); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + public boolean needsUpgrade() { + return needsUpgrade; + } + + public boolean getPrePopulate() { + return needsPrePopulation; + } + + public void clearPrePopulate() { + needsPrePopulation = false; + } + + /** + * Close database connection + */ + public void close() { + if (db == null) { + return; + } + try { + db.close(); + } catch (SQLException e) { + Log.d(TAG, "close exception: " + e.getLocalizedMessage()); + } + } + + public int fetchVersion() { + int version = 0; + try { + Cursor c = db.query( + true, TABLE_DBVERSION, + new String[]{"version"}, + null, null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + version = c.getInt(0); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return version; + } ////////// Salt Functions //////////////// - /** - * Store the salt - * - * @return String version of salt - */ - public String fetchSalt() { - String salt=""; - if (db==null) { return salt; } - try { - Cursor c = db.query(true, TABLE_SALT, new String[] {"salt"}, - null, null, null, null, null,null); - if(c.getCount() > 0) { - c.moveToFirst(); - salt=c.getString(0); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return salt; - } - - /** - * Store the salt into the database. - * - * @param salt String version of the salt - */ - public void storeSalt(String salt) { - ContentValues args = new ContentValues(); - try { - db.delete(TABLE_SALT, "1=1", null); - args.put("salt", salt); - db.insert(TABLE_SALT, null, args); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } + /** + * Store the salt + * + * @return String version of salt + */ + public String fetchSalt() { + String salt = ""; + if (db == null) { + return salt; + } + try { + Cursor c = db.query( + true, TABLE_SALT, new String[]{"salt"}, + null, null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + salt = c.getString(0); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return salt; + } + + /** + * Store the salt into the database. + * + * @param salt String version of the salt + */ + public void storeSalt(String salt) { + ContentValues args = new ContentValues(); + try { + db.delete(TABLE_SALT, "1=1", null); + args.put("salt", salt); + db.insert(TABLE_SALT, null, args); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } ////////// Master Key Functions //////////////// - /** - * - * @return The master key. If none is set, then return an empty string. - */ - public String fetchMasterKey() { - String key=""; - try { - Cursor c = db.query(true, TABLE_MASTER_KEY, new String[] {"encryptedkey"}, - null, null, null, null, null,null); - if(c.getCount() > 0) { - c.moveToFirst(); - key=c.getString(0); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return key; - } - - public void storeMasterKey(String MasterKey) { - ContentValues args = new ContentValues(); - try { - db.delete(TABLE_MASTER_KEY, "1=1", null); - args.put("encryptedkey", MasterKey); - db.insert(TABLE_MASTER_KEY, null, args); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } + /** + * @return The master key. If none is set, then return an empty string. + */ + public String fetchMasterKey() { + String key = ""; + try { + Cursor c = db.query( + true, TABLE_MASTER_KEY, new String[]{"encryptedkey"}, + null, null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + key = c.getString(0); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return key; + } + + public void storeMasterKey(String MasterKey) { + ContentValues args = new ContentValues(); + try { + db.delete(TABLE_MASTER_KEY, "1=1", null); + args.put("encryptedkey", MasterKey); + db.insert(TABLE_MASTER_KEY, null, args); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } //////////Category Functions //////////////// - /** - * Doesn't add the category if it already exists. - * @param entry - * @return row id of the added category - */ - public long addCategory(CategoryEntry entry) { - ContentValues initialValues = new ContentValues(); - - long rowID=-1; - if (db==null) { return rowID; } - Cursor c = - db.query(true, TABLE_CATEGORIES, new String[] { - "id", "name"}, "name='" + entry.name + "'" , null, null, null, null, null); - if (c.getCount() > 0) { - c.moveToFirst(); - rowID = c.getLong(0); - - } else {// there's not already such a category... - initialValues.put("name", entry.name); - - try { - rowID=db.insert(TABLE_CATEGORIES, null, initialValues); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - c.close(); - return rowID; - } - - /** - * - * @param Id id of a category to delete - */ - public void deleteCategory(long Id) { - try { - db.delete(TABLE_CATEGORIES, "id=" + Id, null); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - /** - * - * @return a list of all categories - */ - public List fetchAllCategoryRows(){ - ArrayList ret = new ArrayList(); - if (db==null) { return ret; } - try { - Cursor c = - db.query(TABLE_CATEGORIES, new String[] { - "id", "name"}, - null, null, null, null, null); - int numRows = c.getCount(); - c.moveToFirst(); - for (int i = 0; i < numRows; ++i) { - CategoryEntry row = new CategoryEntry(); - row.id = c.getLong(0); - row.name = c.getString(1); - ret.add(row); - c.moveToNext(); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return ret; - } - - /** - * - * @param Id - * @return A CategoryEntry. If Id was not found then CategoryEntry.id will equal -1. - */ - public CategoryEntry fetchCategory(long Id) { - CategoryEntry row = new CategoryEntry(); - try { - Cursor c = - db.query(true, TABLE_CATEGORIES, new String[] { - "id", "name"}, "id=" + Id, null, null, null, null, null); - if (c.getCount() > 0) { - c.moveToFirst(); - row.id = c.getLong(0); - - row.name = c.getString(1); - } else { - row.id = -1; - row.name = null; - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return row; - } - - public int getCategoryCount(long Id) { - int count = 0; - try { - Cursor c = - db.rawQuery("SELECT count(*) FROM "+TABLE_PASSWORDS+" WHERE category=" + Id, null); - if (c.getCount() > 0) { - c.moveToFirst(); - count = c.getInt(0); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return count; - } - - /** - * - * @param Id - * @param entry - */ - public void updateCategory(long Id, CategoryEntry entry) { - ContentValues args = new ContentValues(); - args.put("name", entry.name); - - try { - db.update(TABLE_CATEGORIES, args, "id=" + Id, null); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - + /** + * Doesn't add the category if it already exists. + * + * @param entry + * @return row id of the added category + */ + public long addCategory(CategoryEntry entry) { + ContentValues initialValues = new ContentValues(); + + long rowID = -1; + if (db == null) { + return rowID; + } + Cursor c = + db.query( + true, TABLE_CATEGORIES, new String[]{ + "id", "name"}, "name='" + entry.name + "'", null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + rowID = c.getLong(0); + + } else {// there's not already such a category... + initialValues.put("name", entry.name); + + try { + rowID = db.insert(TABLE_CATEGORIES, null, initialValues); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + c.close(); + return rowID; + } + + /** + * @param Id id of a category to delete + */ + public void deleteCategory(long Id) { + try { + db.delete(TABLE_CATEGORIES, "id=" + Id, null); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + /** + * @return a list of all categories + */ + public List fetchAllCategoryRows() { + ArrayList ret = new ArrayList(); + if (db == null) { + return ret; + } + try { + Cursor c = + db.query( + TABLE_CATEGORIES, new String[]{ + "id", "name"}, + null, null, null, null, null + ); + int numRows = c.getCount(); + c.moveToFirst(); + for (int i = 0; i < numRows; ++i) { + CategoryEntry row = new CategoryEntry(); + row.id = c.getLong(0); + row.name = c.getString(1); + ret.add(row); + c.moveToNext(); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return ret; + } + + /** + * @param Id + * @return A CategoryEntry. If Id was not found then CategoryEntry.id will equal -1. + */ + public CategoryEntry fetchCategory(long Id) { + CategoryEntry row = new CategoryEntry(); + try { + Cursor c = + db.query( + true, TABLE_CATEGORIES, new String[]{ + "id", "name"}, "id=" + Id, null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + row.id = c.getLong(0); + + row.name = c.getString(1); + } else { + row.id = -1; + row.name = null; + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return row; + } + + public int getCategoryCount(long Id) { + int count = 0; + try { + Cursor c = + db.rawQuery("SELECT count(*) FROM " + TABLE_PASSWORDS + " WHERE category=" + Id, null); + if (c.getCount() > 0) { + c.moveToFirst(); + count = c.getInt(0); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return count; + } + + /** + * @param Id + * @param entry + */ + public void updateCategory(long Id, CategoryEntry entry) { + ContentValues args = new ContentValues(); + args.put("name", entry.name); + + try { + db.update(TABLE_CATEGORIES, args, "id=" + Id, null); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } ////////// Password Functions //////////////// - - /** - * - * @param categoryId if -1 then count all passwords - */ - public int countPasswords(long categoryId) { - int count=0; - try { - String selection=null; - if (categoryId>0) { - selection="category="+categoryId; - } - Cursor c = db.query(TABLE_PASSWORDS, new String[] { - "count(*)"}, - selection, null, null, null, null); - c.moveToFirst(); - count=c.getInt(0); - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - //Log.i(TAG,"count="+count); - return count; - } - - /** - * - * @return A list of all password entries filtered by the CategoryId. - * If CategoryId is 0, then return all entries in the database. - */ - public List fetchAllRows(Long CategoryId){ - ArrayList ret = new ArrayList(); - if (db==null) { return ret; } - try { - Cursor c; - if (CategoryId==0) - { - c = db.query(TABLE_PASSWORDS, new String[] { - "id", "password", "description", "username", "website", - "note", "category", "unique_name", "lastdatetimeedit"}, - null, null, null, null, null); - } else { - c = db.query(TABLE_PASSWORDS, new String[] { - "id", "password", "description", "username", "website", - "note", "category", "unique_name", "lastdatetimeedit"}, - "category="+CategoryId, null, null, null, null); - } - int numRows = c.getCount(); - c.moveToFirst(); - for (int i = 0; i < numRows; ++i) { - PassEntry row = new PassEntry(); - row.id = c.getLong(0); - - row.password = c.getString(1); - row.description = c.getString(2); - row.username = c.getString(3); - row.website = c.getString(4); - row.note = c.getString(5); - - row.category = c.getLong(6); - row.uniqueName = c.getString(7); - row.lastEdited = c.getString(8); - - ret.add(row); - c.moveToNext(); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return ret; - } - - /** - * - * @param Id - * @return The password entry matching the Id. If not found, then - * the returned PassEntry.id will equal -1. - */ - public PassEntry fetchPassword(long Id) { - PassEntry row = new PassEntry(); - try { - Cursor c = - db.query(true, TABLE_PASSWORDS, new String[] { - "id", "password", "description", "username", "website", - "note", "category, unique_name", "lastdatetimeedit"}, - "id=" + Id, null, null, null, null, null); - if (c.getCount() > 0) { - c.moveToFirst(); - row.id = c.getLong(0); - - row.password = c.getString(1); - row.description = c.getString(2); - row.username = c.getString(3); - row.website = c.getString(4); - row.note = c.getString(5); - - row.category = c.getLong(6); - row.uniqueName = c.getString(7); - row.lastEdited = c.getString(8); - } else { - row.id = -1; - row.description = row.password = null; - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return row; - } - - public PassEntry fetchPassword(String uniqueName) { - PassEntry row = new PassEntry(); - row.id = -1; - row.description = row.password = null; - try { - Cursor c = - db.query(true, TABLE_PASSWORDS, new String[] { - "id", "password", "description", "username", "website", - "note", "category", "unique_name", "lastdatetimeedit"}, - "unique_name='" + uniqueName + "'", - null, null, null, null, null); - if (c.getCount() > 0) { - c.moveToFirst(); - row.id = c.getLong(0); - - row.password = c.getString(1); - row.description = c.getString(2); - row.username = c.getString(3); - row.website = c.getString(4); - row.note = c.getString(5); - - row.category = c.getLong(6); - row.uniqueName = c.getString(7); - row.lastEdited = c.getString(8); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return row; - } - - - public ArrayList fetchPackageAccess (long passwordID) { - ArrayList pkgs = new ArrayList(); - Cursor c = null; - try { - c = - db.query(true, TABLE_PACKAGE_ACCESS, new String[] { - "package"}, "id=" + passwordID, - null, null, null, null, null); - if (c.getCount() > 0) { - c.moveToFirst(); - while (! c.isAfterLast()) { - pkgs.add(c.getString(0)); - c.moveToNext(); - } - } - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } finally { - if (c != null) c.close(); - } - - return pkgs; - } - - /** - * Fetch all the package access data into one HashMap. - * - * @return HashMap<Long id, ArrayList<String> package> - */ - public HashMap> fetchPackageAccessAll() { - HashMap> pkgsAll=new HashMap>(); - - if (db==null) { return pkgsAll; } - Cursor c = null; - try { - c = - db.query(true, TABLE_PACKAGE_ACCESS, new String[] { - "id"}, null, null, null, null, null, null); - if (c.getCount() > 0) { - c.moveToFirst(); - while (! c.isAfterLast()) { - Long id=c.getLong(0); - ArrayList pkgs = fetchPackageAccess(id); - if (pkgs!=null) { - pkgsAll.put(id, pkgs); - } - c.moveToNext(); - } - } - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } finally { - if (c != null) c.close(); - } - - return pkgsAll; - } - - public void addPackageAccess (long passwordID, String packageToAdd) { - ContentValues packageAccessValues = new ContentValues (); - packageAccessValues.put("id", passwordID); - packageAccessValues.put("package", packageToAdd); - try { - db.insert(TABLE_PACKAGE_ACCESS, null, packageAccessValues); - } catch (SQLException e) { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - /** - * - * @param Id - * @param entry - * @return Id on success, -1 on failure - */ - public long updatePassword(long Id, PassEntry entry) { - ContentValues args = new ContentValues(); - args.put("description", entry.description); - args.put("username", entry.username); - args.put("password", entry.password); - args.put("website", entry.website); - args.put("note", entry.note); - args.put("unique_name", entry.uniqueName); - DateFormat dateFormatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, - DateFormat.FULL); - Date today = new Date(); - String dateOut = dateFormatter.format(today); - args.put("lastdatetimeedit", dateOut); - try { - db.update(TABLE_PASSWORDS, args, "id=" + Id, null); - } catch (SQLException e) - { - Log.d(TAG,"updatePassword: SQLite exception: " + e.getLocalizedMessage()); - return -1; - } - return Id; - } - - /** - * Only update the category field of the password entry. - * - * @param Id the id of the password entry - * @param newCategoryId the updated category id - */ - public void updatePasswordCategory(long Id, long newCategoryId) { - if (Id<0 || newCategoryId<0) { - //make sure values appear valid - return; - } - ContentValues args = new ContentValues(); - - args.put("category", newCategoryId); - - try { - db.update(TABLE_PASSWORDS, args, "id=" + Id, null); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - /** - * Add a password entry to the database. - * PassEntry.id should be set to 0, unless a specific - * row id is desired. - * - * @param entry PassEntry - * @return long row id of newly added entry, equal to -1 if an error occurred - */ - public long addPassword(PassEntry entry) { - long id = -1; - ContentValues initialValues = new ContentValues(); - if (entry.id!=0) { - initialValues.put("id", entry.id); - } - initialValues.put("category", entry.category); - initialValues.put("password", entry.password); - initialValues.put("description", entry.description); - initialValues.put("username",entry.username); - initialValues.put("website", entry.website); - initialValues.put("note", entry.note); - initialValues.put("unique_name", entry.uniqueName); - DateFormat dateFormatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, - DateFormat.FULL); - Date today = new Date(); - String dateOut = dateFormatter.format(today); - initialValues.put("lastdatetimeedit", dateOut); - - try { - id = db.insertOrThrow(TABLE_PASSWORDS, null, initialValues); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - id=-1; - } - return (id); - } - - /** - * - * @param Id - */ - public void deletePassword(long Id) { - try { - db.delete(TABLE_PASSWORDS, "id=" + Id, null); - db.delete(TABLE_PACKAGE_ACCESS, "id=" + Id, null); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } + /** + * @param categoryId if -1 then count all passwords + */ + public int countPasswords(long categoryId) { + int count = 0; + try { + String selection = null; + if (categoryId > 0) { + selection = "category=" + categoryId; + } + Cursor c = db.query( + TABLE_PASSWORDS, new String[]{ + "count(*)"}, + selection, null, null, null, null + ); + c.moveToFirst(); + count = c.getInt(0); + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + //Log.i(TAG,"count="+count); + return count; + } + + /** + * @return A list of all password entries filtered by the CategoryId. + * If CategoryId is 0, then return all entries in the database. + */ + public List fetchAllRows(Long CategoryId) { + ArrayList ret = new ArrayList(); + if (db == null) { + return ret; + } + try { + Cursor c; + if (CategoryId == 0) { + c = db.query( + TABLE_PASSWORDS, new String[]{ + "id", "password", "description", "username", "website", + "note", "category", "unique_name", "lastdatetimeedit"}, + null, null, null, null, null + ); + } else { + c = db.query( + TABLE_PASSWORDS, new String[]{ + "id", "password", "description", "username", "website", + "note", "category", "unique_name", "lastdatetimeedit"}, + "category=" + CategoryId, null, null, null, null + ); + } + int numRows = c.getCount(); + c.moveToFirst(); + for (int i = 0; i < numRows; ++i) { + PassEntry row = new PassEntry(); + row.id = c.getLong(0); + + row.password = c.getString(1); + row.description = c.getString(2); + row.username = c.getString(3); + row.website = c.getString(4); + row.note = c.getString(5); + + row.category = c.getLong(6); + row.uniqueName = c.getString(7); + row.lastEdited = c.getString(8); + + ret.add(row); + c.moveToNext(); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return ret; + } + + /** + * @param Id + * @return The password entry matching the Id. If not found, then + * the returned PassEntry.id will equal -1. + */ + public PassEntry fetchPassword(long Id) { + PassEntry row = new PassEntry(); + try { + Cursor c = + db.query( + true, TABLE_PASSWORDS, new String[]{ + "id", "password", "description", "username", "website", + "note", "category, unique_name", "lastdatetimeedit"}, + "id=" + Id, null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + row.id = c.getLong(0); + + row.password = c.getString(1); + row.description = c.getString(2); + row.username = c.getString(3); + row.website = c.getString(4); + row.note = c.getString(5); + + row.category = c.getLong(6); + row.uniqueName = c.getString(7); + row.lastEdited = c.getString(8); + } else { + row.id = -1; + row.description = row.password = null; + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return row; + } + + public PassEntry fetchPassword(String uniqueName) { + PassEntry row = new PassEntry(); + row.id = -1; + row.description = row.password = null; + try { + Cursor c = + db.query( + true, TABLE_PASSWORDS, new String[]{ + "id", "password", "description", "username", "website", + "note", "category", "unique_name", "lastdatetimeedit"}, + "unique_name='" + uniqueName + "'", + null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + row.id = c.getLong(0); + + row.password = c.getString(1); + row.description = c.getString(2); + row.username = c.getString(3); + row.website = c.getString(4); + row.note = c.getString(5); + + row.category = c.getLong(6); + row.uniqueName = c.getString(7); + row.lastEdited = c.getString(8); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return row; + } + + public ArrayList fetchPackageAccess(long passwordID) { + ArrayList pkgs = new ArrayList(); + Cursor c = null; + try { + c = + db.query( + true, TABLE_PACKAGE_ACCESS, new String[]{ + "package"}, "id=" + passwordID, + null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + while (!c.isAfterLast()) { + pkgs.add(c.getString(0)); + c.moveToNext(); + } + } + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } finally { + if (c != null) { + c.close(); + } + } + + return pkgs; + } + + /** + * Fetch all the package access data into one HashMap. + * + * @return HashMap<Long id, ArrayList<String> package> + */ + public HashMap> fetchPackageAccessAll() { + HashMap> pkgsAll = new HashMap>(); + + if (db == null) { + return pkgsAll; + } + Cursor c = null; + try { + c = + db.query( + true, TABLE_PACKAGE_ACCESS, new String[]{ + "id"}, null, null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + while (!c.isAfterLast()) { + Long id = c.getLong(0); + ArrayList pkgs = fetchPackageAccess(id); + if (pkgs != null) { + pkgsAll.put(id, pkgs); + } + c.moveToNext(); + } + } + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } finally { + if (c != null) { + c.close(); + } + } + + return pkgsAll; + } + + public void addPackageAccess(long passwordID, String packageToAdd) { + ContentValues packageAccessValues = new ContentValues(); + packageAccessValues.put("id", passwordID); + packageAccessValues.put("package", packageToAdd); + try { + db.insert(TABLE_PACKAGE_ACCESS, null, packageAccessValues); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + /** + * @param Id + * @param entry + * @return Id on success, -1 on failure + */ + public long updatePassword(long Id, PassEntry entry) { + ContentValues args = new ContentValues(); + args.put("description", entry.description); + args.put("username", entry.username); + args.put("password", entry.password); + args.put("website", entry.website); + args.put("note", entry.note); + args.put("unique_name", entry.uniqueName); + DateFormat dateFormatter = DateFormat.getDateTimeInstance( + DateFormat.DEFAULT, + DateFormat.FULL + ); + Date today = new Date(); + String dateOut = dateFormatter.format(today); + args.put("lastdatetimeedit", dateOut); + try { + db.update(TABLE_PASSWORDS, args, "id=" + Id, null); + } catch (SQLException e) { + Log.d(TAG, "updatePassword: SQLite exception: " + e.getLocalizedMessage()); + return -1; + } + return Id; + } + + /** + * Only update the category field of the password entry. + * + * @param Id the id of the password entry + * @param newCategoryId the updated category id + */ + public void updatePasswordCategory(long Id, long newCategoryId) { + if (Id < 0 || newCategoryId < 0) { + //make sure values appear valid + return; + } + ContentValues args = new ContentValues(); + + args.put("category", newCategoryId); + + try { + db.update(TABLE_PASSWORDS, args, "id=" + Id, null); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + /** + * Add a password entry to the database. + * PassEntry.id should be set to 0, unless a specific + * row id is desired. + * + * @param entry PassEntry + * @return long row id of newly added entry, equal to -1 if an error occurred + */ + public long addPassword(PassEntry entry) { + long id = -1; + ContentValues initialValues = new ContentValues(); + if (entry.id != 0) { + initialValues.put("id", entry.id); + } + initialValues.put("category", entry.category); + initialValues.put("password", entry.password); + initialValues.put("description", entry.description); + initialValues.put("username", entry.username); + initialValues.put("website", entry.website); + initialValues.put("note", entry.note); + initialValues.put("unique_name", entry.uniqueName); + DateFormat dateFormatter = DateFormat.getDateTimeInstance( + DateFormat.DEFAULT, + DateFormat.FULL + ); + Date today = new Date(); + String dateOut = dateFormatter.format(today); + initialValues.put("lastdatetimeedit", dateOut); + + try { + id = db.insertOrThrow(TABLE_PASSWORDS, null, initialValues); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + id = -1; + } + return (id); + } + + /** + * @param Id + */ + public void deletePassword(long Id) { + try { + db.delete(TABLE_PASSWORDS, "id=" + Id, null); + db.delete(TABLE_PACKAGE_ACCESS, "id=" + Id, null); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } //////////Cipher Access Functions //////////////// - /** - * Add a package to the list of packages allowed to use the encrypt/decrypt - * cipher services. - * - * @param packageToAdd - * @param expiration set to 0 if no expiration, otherwise epoch time - */ - public void addCipherAccess (String packageToAdd, long expiration) { - ContentValues initialValues = new ContentValues (); - initialValues.put("packagename", packageToAdd); - initialValues.put("expires", expiration); - DateFormat dateFormatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, - DateFormat.FULL); - Date today = new Date(); - String dateOut = dateFormatter.format(today); - initialValues.put("dateadded", dateOut); - try { - db.insert(TABLE_CIPHER_ACCESS, null, initialValues); - } catch (SQLException e) { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - /** - * Fetch the cipher access for a package. This determines if the package - * is allowed to use encrypt/decrypt services. - * - * @param packageName - * @return -1 if not found, 0 if no expiration, otherwise epoch date of expiration - */ - public long fetchCipherAccess(String packageName) { - long expires=-1; // default to not found - try { - Cursor c = db.query(true, TABLE_CIPHER_ACCESS, new String[] {"expires"}, - "packagename="+packageName, null, null, null, null,null); - if(c.getCount() > 0) { - c.moveToFirst(); - expires=c.getLong(0); - } - c.close(); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - return expires; - } - /** - * Begin a transaction on an open database. - * - * @return true if successful - */ - public boolean beginTransaction() { - try { - db.execSQL("begin transaction;"); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - return false; - } - return true; - } - - /** - * Commit all changes since the begin transaction on an - * open database. - */ - public void commit() { - try { - db.execSQL("commit;"); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } - - /** - * Rollback all changes since the begin transaction on an - * open database. - */ - public void rollback() { - try { - db.execSQL("rollback;"); - } catch (SQLException e) - { - Log.d(TAG,"SQLite exception: " + e.getLocalizedMessage()); - } - } + /** + * Add a package to the list of packages allowed to use the encrypt/decrypt + * cipher services. + * + * @param packageToAdd + * @param expiration set to 0 if no expiration, otherwise epoch time + */ + public void addCipherAccess(String packageToAdd, long expiration) { + ContentValues initialValues = new ContentValues(); + initialValues.put("packagename", packageToAdd); + initialValues.put("expires", expiration); + DateFormat dateFormatter = DateFormat.getDateTimeInstance( + DateFormat.DEFAULT, + DateFormat.FULL + ); + Date today = new Date(); + String dateOut = dateFormatter.format(today); + initialValues.put("dateadded", dateOut); + try { + db.insert(TABLE_CIPHER_ACCESS, null, initialValues); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + /** + * Fetch the cipher access for a package. This determines if the package + * is allowed to use encrypt/decrypt services. + * + * @param packageName + * @return -1 if not found, 0 if no expiration, otherwise epoch date of expiration + */ + public long fetchCipherAccess(String packageName) { + long expires = -1; // default to not found + try { + Cursor c = db.query( + true, TABLE_CIPHER_ACCESS, new String[]{"expires"}, + "packagename=" + packageName, null, null, null, null, null + ); + if (c.getCount() > 0) { + c.moveToFirst(); + expires = c.getLong(0); + } + c.close(); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + return expires; + } + + /** + * Begin a transaction on an open database. + * + * @return true if successful + */ + public boolean beginTransaction() { + try { + db.execSQL("begin transaction;"); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + return false; + } + return true; + } + + /** + * Commit all changes since the begin transaction on an + * open database. + */ + public void commit() { + try { + db.execSQL("commit;"); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } + + /** + * Rollback all changes since the begin transaction on an + * open database. + */ + public void rollback() { + try { + db.execSQL("rollback;"); + } catch (SQLException e) { + Log.d(TAG, "SQLite exception: " + e.getLocalizedMessage()); + } + } } diff --git a/Safe/src/org/openintents/safe/FrontDoor.java b/Safe/src/org/openintents/safe/FrontDoor.java index d2360bba..00b40c37 100644 --- a/Safe/src/org/openintents/safe/FrontDoor.java +++ b/Safe/src/org/openintents/safe/FrontDoor.java @@ -4,14 +4,14 @@ * The main activity prior to version 1.2.4 was ".FrontDoor". Home screens * may still contain a direct link to the old activity, therefore this class * must never be renamed or moved. - * + *

* Prior to version 1.3.1, activity-alias was used. Unfortunately with that in use * the application would not automatically launch from Eclipse and would not debug * correctly. - * + *

* This class is derived from .Safe which contains the actual * implementation. -*/ + */ public class FrontDoor extends Safe { } diff --git a/Safe/src/org/openintents/safe/Help.java b/Safe/src/org/openintents/safe/Help.java index 6bb844bc..0a5c0078 100644 --- a/Safe/src/org/openintents/safe/Help.java +++ b/Safe/src/org/openintents/safe/Help.java @@ -16,11 +16,6 @@ */ package org.openintents.safe; -import java.io.IOException; -import java.io.InputStream; - -import org.openintents.intents.CryptoIntents; - import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; @@ -32,131 +27,144 @@ import android.view.MenuItem; import android.webkit.WebView; +import java.io.IOException; +import java.io.InputStream; + +import org.openintents.intents.CryptoIntents; + /** * This activity shows a help dialog to describe the application. - * + * * @author Randy McEoin */ public class Help extends Activity { - private static boolean debug = false; - private static String TAG = "Help"; - - // Menu Item order - public static final int CLOSE_HELP_INDEX = Menu.FIRST; - - Intent frontdoor; - private Intent restartTimerIntent=null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent (CryptoIntents.ACTION_RESTART_TIMER); - - //Setup layout - setContentView(R.layout.help); - String title = getResources().getString(R.string.app_name) + " - " + - getResources().getString(R.string.help); - setTitle(title); - - - // Programmatically load text from an asset and place it into the - // text view. Note that the text we are loading is ASCII, so we - // need to convert it to UTF-16. - try { - InputStream is = getAssets().open("help.html"); - - // We guarantee that the available method returns the total - // size of the asset... of course, this does mean that a single - // asset can't be more than 2 gigs. - int size = is.available(); - - // Read the entire asset into a local byte buffer. - byte[] buffer = new byte[size]; - is.read(buffer); - is.close(); - - // Convert the buffer into a Java string. - String text = new String(buffer); - - final String mimeType = "text/html"; - final String encoding = "utf-8"; - - // Finally stick the string into the text view. - WebView wv = (WebView)findViewById(R.id.help); - wv.loadData(text, mimeType, encoding); - } catch (IOException e) { - // Should never happen! - throw new RuntimeException(e); - } - - } - - @Override - protected void onPause() { - super.onPause(); - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (debug) Log.d(TAG,"onResume()"); - - if (CategoryList.isSignedIn()==false) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - menu.add(0,CLOSE_HELP_INDEX, 0, R.string.close) - .setIcon(android.R.drawable.ic_menu_close_clear_cancel) - .setShortcut('0', 'w'); - - return super.onCreateOptionsMenu(menu); - } - public boolean onOptionsItemSelected(MenuItem item) { - switch(item.getItemId()) { - case CLOSE_HELP_INDEX: - finish(); - break; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (debug) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + private static boolean debug = false; + private static String TAG = "Help"; + + // Menu Item order + public static final int CLOSE_HELP_INDEX = Menu.FIRST; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + //Setup layout + setContentView(R.layout.help); + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.help); + setTitle(title); + + // Programmatically load text from an asset and place it into the + // text view. Note that the text we are loading is ASCII, so we + // need to convert it to UTF-16. + try { + InputStream is = getAssets().open("help.html"); + + // We guarantee that the available method returns the total + // size of the asset... of course, this does mean that a single + // asset can't be more than 2 gigs. + int size = is.available(); + + // Read the entire asset into a local byte buffer. + byte[] buffer = new byte[size]; + is.read(buffer); + is.close(); + + // Convert the buffer into a Java string. + String text = new String(buffer); + + final String mimeType = "text/html"; + final String encoding = "utf-8"; + + // Finally stick the string into the text view. + WebView wv = (WebView) findViewById(R.id.help); + wv.loadData(text, mimeType, encoding); + } catch (IOException e) { + // Should never happen! + throw new RuntimeException(e); + } + + } + + @Override + protected void onPause() { + super.onPause(); + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + + if (CategoryList.isSignedIn() == false) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + menu.add(0, CLOSE_HELP_INDEX, 0, R.string.close) + .setIcon(android.R.drawable.ic_menu_close_clear_cancel) + .setShortcut('0', 'w'); + + return super.onCreateOptionsMenu(menu); + } + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case CLOSE_HELP_INDEX: + finish(); + break; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // startActivity(frontdoor); - }else{ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } -} \ No newline at end of file + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } +} diff --git a/Safe/src/org/openintents/safe/InputStreamData.java b/Safe/src/org/openintents/safe/InputStreamData.java index 3f69fe9f..419e08d4 100644 --- a/Safe/src/org/openintents/safe/InputStreamData.java +++ b/Safe/src/org/openintents/safe/InputStreamData.java @@ -5,10 +5,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.InputStream; -import java.io.OutputStream; - public class InputStreamData { private String filename; diff --git a/Safe/src/org/openintents/safe/IntentHandler.java b/Safe/src/org/openintents/safe/IntentHandler.java index 8fa2b2f8..bc9c6f35 100644 --- a/Safe/src/org/openintents/safe/IntentHandler.java +++ b/Safe/src/org/openintents/safe/IntentHandler.java @@ -15,14 +15,6 @@ */ package org.openintents.safe; - -import java.util.ArrayList; -import java.util.Arrays; - -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.dialog.DialogHostingActivity; -import org.openintents.safe.password.Master; - import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; @@ -32,285 +24,324 @@ import android.util.Log; import android.widget.Toast; +import java.util.ArrayList; +import java.util.Arrays; + +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.dialog.DialogHostingActivity; +import org.openintents.safe.password.Master; /** * FrontDoor Activity - * + *

* This activity just acts as a splash screen and gets the password from the * user that will be used to decrypt/encrypt password entries. - * + * * @author Steven Osborn - http://steven.bitsetters.com */ public class IntentHandler extends Activity { - private static final boolean debug = true; - private static String TAG = "IntentHandler"; - - private static final int REQUEST_CODE_ASK_PASSWORD = 1; - private static final int REQUEST_CODE_ALLOW_EXTERNAL_ACCESS = 2; - - private CryptoHelper ch; - - SharedPreferences mPreferences; - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - if (debug) Log.d(TAG, "onCreate("+icicle+")"); - - mPreferences = PreferenceManager.getDefaultSharedPreferences(this); - - if (Passwords.Initialize(this)==false) { - finish(); - } - } - - - //currently only handles result from askPassword function. - protected void onActivityResult (int requestCode, int resultCode, Intent data) { - if (debug) Log.d(TAG, "onActivityResult: requestCode == " + requestCode + ", resultCode == " + resultCode); - - switch (requestCode) { - case REQUEST_CODE_ASK_PASSWORD: - if (resultCode == RESULT_OK) { - if (debug) Log.d(TAG,"RESULT_OK"); - actionDispatch(); - - } else { // resultCode == RESULT_CANCELED, which means the user hit Back at AskPassword - if (debug) Log.d(TAG,"RESULT_CANCELED"); - moveTaskToBack(true); - setResult(RESULT_CANCELED); - finish(); - } - break; - case REQUEST_CODE_ALLOW_EXTERNAL_ACCESS: - // Check again, regardless whether user pressed "OK" or "Cancel". - // Also, DialogHostingActivity never returns a resultCode different than - // RESULT_CANCELED. - if (debug) Log.i(TAG, "actionDispatch called right now"); - actionDispatch(); - break; - } - - } - - /** - * - */ - private void showDialogAllowExternalAccess() { - Intent i = new Intent(this, DialogHostingActivity.class); - i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_ALLOW_EXTERNAL_ACCESS); - this.startActivityForResult(i, REQUEST_CODE_ALLOW_EXTERNAL_ACCESS); - } - - protected void actionDispatch () { - final Intent thisIntent = getIntent(); - final String action = thisIntent.getAction(); - Intent callbackIntent = getIntent(); - int callbackResult = RESULT_CANCELED; - - if (debug) Log.d(TAG,"actionDispatch()"); - if ((Master.getSalt()==null) || (Master.getSalt()=="")) { - return; - } - if (ch == null) { - ch = new CryptoHelper(); - } - try { - ch.init(CryptoHelper.EncryptionMedium,Master.getSalt()); - ch.setPassword(Master.getMasterKey()); - } catch (CryptoHelperException e1) { - e1.printStackTrace(); - Toast.makeText(this, getString(R.string.crypto_error) - + e1.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - - boolean externalAccess = mPreferences.getBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, false); - - if (action == null || action.equals(Intent.ACTION_MAIN)){ - //TODO: When launched from debugger, action is null. Other such cases? - Intent i = new Intent(getApplicationContext(), - CategoryList.class); - startActivity(i); - } else if (action.equals(CryptoIntents.ACTION_AUTOLOCK)) { - if (debug) Log.d(TAG,"autolock"); - finish(); - } else if (externalAccess){ - - // which action? - if (action.equals (CryptoIntents.ACTION_ENCRYPT)) { - callbackResult = encryptIntent(thisIntent, callbackIntent); - } else if (action.equals (CryptoIntents.ACTION_DECRYPT)) { - callbackResult = decryptIntent(thisIntent, callbackIntent); - } else if (action.equals (CryptoIntents.ACTION_GET_PASSWORD) - || action.equals (CryptoIntents.ACTION_SET_PASSWORD)) { - try { - callbackIntent = getSetPassword (thisIntent, callbackIntent); - callbackResult = RESULT_OK; - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString(), e); - Toast.makeText(IntentHandler.this, - "There was a crypto error while retreiving the requested password: " + e.getMessage(), - Toast.LENGTH_SHORT).show(); - } catch (Exception e) { - Log.e(TAG, e.toString(), e); - //TODO: Turn this into a proper error dialog. - Toast.makeText(IntentHandler.this, - "There was an error in retreiving the requested password: " + e.getMessage(), - Toast.LENGTH_SHORT).show(); - } - } - setResult(callbackResult, callbackIntent); - } - finish(); - } - - - /** - * Encrypt all supported fields in the intent and return the result in callbackIntent. - * - * This is supposed to be called by outside functions, so we encrypt using a random session key. - * - * @param thisIntent - * @param callbackIntent - * @return callbackResult - */ - private int encryptIntent(final Intent thisIntent, Intent callbackIntent) { - if (debug) - Log.d(TAG, "encryptIntent()"); - - int callbackResult = RESULT_CANCELED; - try { - if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT)) { - // get the body text out of the extras. - String inputBody = thisIntent.getStringExtra (CryptoIntents.EXTRA_TEXT); - if (debug) Log.d(TAG,"inputBody="+inputBody); - String outputBody = ""; - outputBody = ch.encryptWithSessionKey (inputBody); - // stash the encrypted text in the extra - callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT, outputBody); - } - - if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT_ARRAY)) { - String[] in = thisIntent.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); - if (debug) Log.d(TAG,"in="+Arrays.toString(in)); - String[] out = new String[in.length]; - for (int i = 0; i < in.length; i++) { - if (in[i] != null) { - out[i] = ch.encryptWithSessionKey(in[i]); - } - } - if (debug) Log.d(TAG,"out="+Arrays.toString(out)); - callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, out); - } - - if (thisIntent.getData() != null) { - // Encrypt file from file URI - Uri fileUri = thisIntent.getData(); - - Uri newFileUri = ch.encryptFileWithSessionKey(getContentResolver(), fileUri); - - callbackIntent.setData(newFileUri); - } - - if (thisIntent.hasExtra(CryptoIntents.EXTRA_SESSION_KEY)) { - String sessionkey = ch.getCurrentSessionKey(); - if (sessionkey==null) { - return RESULT_CANCELED; - } - callbackIntent.putExtra(CryptoIntents.EXTRA_SESSION_KEY, sessionkey); - - // Warning! This overwrites any data intent set previously. - callbackIntent.setData(CryptoContentProvider.CONTENT_URI); - } - - callbackResult = RESULT_OK; - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString()); - } - return callbackResult; - } - - /** - * Decrypt all supported fields in the intent and return the result in callbackIntent. - * - * @param thisIntent - * @param callbackIntent - * @return callbackResult - */ - private int decryptIntent(final Intent thisIntent, Intent callbackIntent) { - int callbackResult = RESULT_CANCELED; - try { - - if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT)) { - // get the body text out of the extras. - String inputBody = thisIntent.getStringExtra (CryptoIntents.EXTRA_TEXT); - String outputBody = ""; - outputBody = ch.decryptWithSessionKey (inputBody); - // stash the encrypted text in the extra - callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT, outputBody); - } - - if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT_ARRAY)) { - String[] in = thisIntent.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); - String[] out = new String[in.length]; - for (int i = 0; i < in.length; i++) { - if (in[i] != null) { - out[i] = ch.decryptWithSessionKey(in[i]); - } - } - callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, out); - } - - if (thisIntent.getData() != null) { - // Decrypt file from file URI - Uri fileUri = thisIntent.getData(); - - Uri newFileUri = ch.decryptFileWithSessionKey(this, fileUri); - - callbackIntent.setData(newFileUri); - } - - if (thisIntent.hasExtra(CryptoIntents.EXTRA_SESSION_KEY)) { - String sessionkey = ch.getCurrentSessionKey(); - callbackIntent.putExtra(CryptoIntents.EXTRA_SESSION_KEY, sessionkey); - - // Warning! This overwrites any data intent set previously. - callbackIntent.setData(CryptoContentProvider.CONTENT_URI); - } - - callbackResult = RESULT_OK; - } catch (CryptoHelperException e) { - Log.e(TAG, e.toString()); - } - return callbackResult; - } - - private Intent getSetPassword (Intent thisIntent, Intent callbackIntent) throws CryptoHelperException, Exception { - String action = thisIntent.getAction(); - //TODO: Consider moving this elsewhere. Maybe DBHelper? Also move strings to resource. - //DBHelper dbHelper = new DBHelper(this); - if (debug) Log.d(TAG, "GET_or_SET_PASSWORD"); - String username = null; - String password = null; - - String clearUniqueName = thisIntent.getStringExtra (CryptoIntents.EXTRA_UNIQUE_NAME); - - if (clearUniqueName == null) throw new Exception ("EXTRA_UNIQUE_NAME not set."); - - PassEntry row = Passwords.findPassWithUniqueName(clearUniqueName); - boolean passExists = (row!=null); - - String callingPackage = getCallingPackage(); - if (passExists) { // check for permission to access this password. - ArrayList packageAccess = Passwords.getPackageAccess(row.id); - if ((packageAccess==null) || - (! PassEntry.checkPackageAccess(packageAccess, callingPackage))) { - throw new Exception ("It is currently not permissible for this application to request this password."); - } - /*TODO: check if this package is in the package_access table corresponding to this password: + private static final boolean debug = true; + private static String TAG = "IntentHandler"; + + private static final int REQUEST_CODE_ASK_PASSWORD = 1; + private static final int REQUEST_CODE_ALLOW_EXTERNAL_ACCESS = 2; + + private CryptoHelper ch; + + SharedPreferences mPreferences; + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + if (debug) { + Log.d(TAG, "onCreate(" + icicle + ")"); + } + + mPreferences = PreferenceManager.getDefaultSharedPreferences(this); + + if (Passwords.Initialize(this) == false) { + finish(); + } + } + + //currently only handles result from askPassword function. + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (debug) { + Log.d(TAG, "onActivityResult: requestCode == " + requestCode + ", resultCode == " + resultCode); + } + + switch (requestCode) { + case REQUEST_CODE_ASK_PASSWORD: + if (resultCode == RESULT_OK) { + if (debug) { + Log.d(TAG, "RESULT_OK"); + } + actionDispatch(); + + } else { // resultCode == RESULT_CANCELED, which means the user hit Back at AskPassword + if (debug) { + Log.d(TAG, "RESULT_CANCELED"); + } + moveTaskToBack(true); + setResult(RESULT_CANCELED); + finish(); + } + break; + case REQUEST_CODE_ALLOW_EXTERNAL_ACCESS: + // Check again, regardless whether user pressed "OK" or "Cancel". + // Also, DialogHostingActivity never returns a resultCode different than + // RESULT_CANCELED. + if (debug) { + Log.i(TAG, "actionDispatch called right now"); + } + actionDispatch(); + break; + } + + } + + /** + * + */ + private void showDialogAllowExternalAccess() { + Intent i = new Intent(this, DialogHostingActivity.class); + i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_ALLOW_EXTERNAL_ACCESS); + this.startActivityForResult(i, REQUEST_CODE_ALLOW_EXTERNAL_ACCESS); + } + + protected void actionDispatch() { + final Intent thisIntent = getIntent(); + final String action = thisIntent.getAction(); + Intent callbackIntent = getIntent(); + int callbackResult = RESULT_CANCELED; + + if (debug) { + Log.d(TAG, "actionDispatch()"); + } + if ((Master.getSalt() == null) || (Master.getSalt() == "")) { + return; + } + if (ch == null) { + ch = new CryptoHelper(); + } + try { + ch.init(CryptoHelper.EncryptionMedium, Master.getSalt()); + ch.setPassword(Master.getMasterKey()); + } catch (CryptoHelperException e1) { + e1.printStackTrace(); + Toast.makeText( + this, getString(R.string.crypto_error) + + e1.getMessage(), Toast.LENGTH_SHORT + ).show(); + return; + } + + boolean externalAccess = mPreferences.getBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, false); + + if (action == null || action.equals(Intent.ACTION_MAIN)) { + //TODO: When launched from debugger, action is null. Other such cases? + Intent i = new Intent( + getApplicationContext(), + CategoryList.class + ); + startActivity(i); + } else if (action.equals(CryptoIntents.ACTION_AUTOLOCK)) { + if (debug) { + Log.d(TAG, "autolock"); + } + finish(); + } else if (externalAccess) { + + // which action? + if (action.equals(CryptoIntents.ACTION_ENCRYPT)) { + callbackResult = encryptIntent(thisIntent, callbackIntent); + } else if (action.equals(CryptoIntents.ACTION_DECRYPT)) { + callbackResult = decryptIntent(thisIntent, callbackIntent); + } else if (action.equals(CryptoIntents.ACTION_GET_PASSWORD) + || action.equals(CryptoIntents.ACTION_SET_PASSWORD)) { + try { + callbackIntent = getSetPassword(thisIntent, callbackIntent); + callbackResult = RESULT_OK; + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString(), e); + Toast.makeText( + IntentHandler.this, + "There was a crypto error while retreiving the requested password: " + e.getMessage(), + Toast.LENGTH_SHORT + ).show(); + } catch (Exception e) { + Log.e(TAG, e.toString(), e); + //TODO: Turn this into a proper error dialog. + Toast.makeText( + IntentHandler.this, + "There was an error in retreiving the requested password: " + e.getMessage(), + Toast.LENGTH_SHORT + ).show(); + } + } + setResult(callbackResult, callbackIntent); + } + finish(); + } + + /** + * Encrypt all supported fields in the intent and return the result in callbackIntent. + *

+ * This is supposed to be called by outside functions, so we encrypt using a random session key. + * + * @param thisIntent + * @param callbackIntent + * @return callbackResult + */ + private int encryptIntent(final Intent thisIntent, Intent callbackIntent) { + if (debug) { + Log.d(TAG, "encryptIntent()"); + } + + int callbackResult = RESULT_CANCELED; + try { + if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT)) { + // get the body text out of the extras. + String inputBody = thisIntent.getStringExtra(CryptoIntents.EXTRA_TEXT); + if (debug) { + Log.d(TAG, "inputBody=" + inputBody); + } + String outputBody = ""; + outputBody = ch.encryptWithSessionKey(inputBody); + // stash the encrypted text in the extra + callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT, outputBody); + } + + if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT_ARRAY)) { + String[] in = thisIntent.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); + if (debug) { + Log.d(TAG, "in=" + Arrays.toString(in)); + } + String[] out = new String[in.length]; + for (int i = 0; i < in.length; i++) { + if (in[i] != null) { + out[i] = ch.encryptWithSessionKey(in[i]); + } + } + if (debug) { + Log.d(TAG, "out=" + Arrays.toString(out)); + } + callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, out); + } + + if (thisIntent.getData() != null) { + // Encrypt file from file URI + Uri fileUri = thisIntent.getData(); + + Uri newFileUri = ch.encryptFileWithSessionKey(getContentResolver(), fileUri); + + callbackIntent.setData(newFileUri); + } + + if (thisIntent.hasExtra(CryptoIntents.EXTRA_SESSION_KEY)) { + String sessionkey = ch.getCurrentSessionKey(); + if (sessionkey == null) { + return RESULT_CANCELED; + } + callbackIntent.putExtra(CryptoIntents.EXTRA_SESSION_KEY, sessionkey); + + // Warning! This overwrites any data intent set previously. + callbackIntent.setData(CryptoContentProvider.CONTENT_URI); + } + + callbackResult = RESULT_OK; + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + return callbackResult; + } + + /** + * Decrypt all supported fields in the intent and return the result in callbackIntent. + * + * @param thisIntent + * @param callbackIntent + * @return callbackResult + */ + private int decryptIntent(final Intent thisIntent, Intent callbackIntent) { + int callbackResult = RESULT_CANCELED; + try { + + if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT)) { + // get the body text out of the extras. + String inputBody = thisIntent.getStringExtra(CryptoIntents.EXTRA_TEXT); + String outputBody = ""; + outputBody = ch.decryptWithSessionKey(inputBody); + // stash the encrypted text in the extra + callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT, outputBody); + } + + if (thisIntent.hasExtra(CryptoIntents.EXTRA_TEXT_ARRAY)) { + String[] in = thisIntent.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); + String[] out = new String[in.length]; + for (int i = 0; i < in.length; i++) { + if (in[i] != null) { + out[i] = ch.decryptWithSessionKey(in[i]); + } + } + callbackIntent.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, out); + } + + if (thisIntent.getData() != null) { + // Decrypt file from file URI + Uri fileUri = thisIntent.getData(); + + Uri newFileUri = ch.decryptFileWithSessionKey(this, fileUri); + + callbackIntent.setData(newFileUri); + } + + if (thisIntent.hasExtra(CryptoIntents.EXTRA_SESSION_KEY)) { + String sessionkey = ch.getCurrentSessionKey(); + callbackIntent.putExtra(CryptoIntents.EXTRA_SESSION_KEY, sessionkey); + + // Warning! This overwrites any data intent set previously. + callbackIntent.setData(CryptoContentProvider.CONTENT_URI); + } + + callbackResult = RESULT_OK; + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + return callbackResult; + } + + private Intent getSetPassword(Intent thisIntent, Intent callbackIntent) throws CryptoHelperException, Exception { + String action = thisIntent.getAction(); + //TODO: Consider moving this elsewhere. Maybe DBHelper? Also move strings to resource. + //DBHelper dbHelper = new DBHelper(this); + if (debug) { + Log.d(TAG, "GET_or_SET_PASSWORD"); + } + String username = null; + String password = null; + + String clearUniqueName = thisIntent.getStringExtra(CryptoIntents.EXTRA_UNIQUE_NAME); + + if (clearUniqueName == null) { + throw new Exception("EXTRA_UNIQUE_NAME not set."); + } + + PassEntry row = Passwords.findPassWithUniqueName(clearUniqueName); + boolean passExists = (row != null); + + String callingPackage = getCallingPackage(); + if (passExists) { // check for permission to access this password. + ArrayList packageAccess = Passwords.getPackageAccess(row.id); + if ((packageAccess == null) || + (!PassEntry.checkPackageAccess(packageAccess, callingPackage))) { + throw new Exception("It is currently not permissible for this application to request this password."); + } + /*TODO: check if this package is in the package_access table corresponding to this password: * "Application 'org.syntaxpolice.ServiceTest' wants to access the password for 'opensocial'. [ ] Grant access this time. @@ -318,133 +349,149 @@ private Intent getSetPassword (Intent thisIntent, Intent callbackIntent) throws [ ] Always grant access to all passwords in org.syntaxpolice.ServiceTest category? [ ] Don't grant access" */ - } else { - row = new PassEntry(); - } - - if (action.equals (CryptoIntents.ACTION_GET_PASSWORD)) { - if (passExists) { - username = row.plainUsername; - password = row.plainPassword; - } else throw new Exception ("Could not find password with the unique name: " + clearUniqueName); - - // stashing the return values: - callbackIntent.putExtra(CryptoIntents.EXTRA_USERNAME, username); - callbackIntent.putExtra(CryptoIntents.EXTRA_PASSWORD, password); - } else if (action.equals (CryptoIntents.ACTION_SET_PASSWORD)) { - String clearUsername = thisIntent.getStringExtra (CryptoIntents.EXTRA_USERNAME); - String clearPassword = thisIntent.getStringExtra (CryptoIntents.EXTRA_PASSWORD); - if (clearPassword == null) { - throw new Exception ("PASSWORD extra must be set."); - } - row.plainUsername = clearUsername == null ? "" : clearUsername; - row.plainPassword = clearPassword; - // since this package is setting the password, it automatically gets access to it: - if (passExists) { //exists already - if (clearUsername.equals("") && clearPassword.equals("")) { - Passwords.deletePassEntry(row.id); - } else { - Passwords.putPassEntry(row); - } - } else {// add a new one - row.plainUniqueName = clearUniqueName; - row.plainDescription=clearUniqueName; //for display purposes - // TODO: Should we send these fields in extras also? If so, probably not using - // the openintents namespace? If another application were to implement a keystore - // they might not want to use these. - row.plainWebsite = ""; - row.plainNote = ""; - - String category="Application Data"; - CategoryEntry c = Passwords.getCategoryEntryByName(category); - if (c==null) { - c = new CategoryEntry(); - c.plainName = "Application Data"; - c.id = Passwords.putCategoryEntry(c); //doesn't add category if it already exists - } - row.category = c.id; - row.id = 0; // entry is truly new - row.id = Passwords.putPassEntry(row); - } - ArrayList packageAccess = Passwords.getPackageAccess(row.id); - if ((packageAccess==null) || - (! PassEntry.checkPackageAccess(packageAccess, callingPackage))) { - Passwords.addPackageAccess(row.id, callingPackage); - } - - } - return (callbackIntent); - } - - @Override - protected void onPause() { - super.onPause(); - - if (debug) - Log.d(TAG, "onPause()"); - } - - @Override - protected void onResume() { - super.onResume(); - - if (debug) - Log.d(TAG, "onResume()"); - startUp(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - } - - - /** - * @return - */ - private boolean isIntentLocal() { - String action = getIntent().getAction(); - boolean isLocal = action == null || action.equals(Intent.ACTION_MAIN) || - action.equals(CryptoIntents.ACTION_AUTOLOCK); - if (debug) Log.d(TAG,"isLocal="+isLocal+", action="+action); - return isLocal; - } - - public void startUp() - { - boolean askPassIsLocal=isIntentLocal(); - - if (Master.getMasterKey() == null) { - boolean promptforpassword = getIntent().getBooleanExtra(CryptoIntents.EXTRA_PROMPT, true); - if (debug) Log.d(TAG, "Prompt for password: " + promptforpassword); - if (promptforpassword) { - if (debug) Log.d(TAG, "ask for password"); - Intent askPass = new Intent(getApplicationContext(), - AskPassword.class); - - String inputBody = getIntent().getStringExtra (CryptoIntents.EXTRA_TEXT); - - askPass.putExtra (CryptoIntents.EXTRA_TEXT, inputBody); - askPass.putExtra (AskPassword.EXTRA_IS_LOCAL, askPassIsLocal); - //TODO: Is there a way to make sure all the extras are set? - startActivityForResult (askPass, REQUEST_CODE_ASK_PASSWORD); - } else { - if (debug) Log.d(TAG, "ask for password"); - // Don't prompt but cancel - setResult(RESULT_CANCELED); - finish(); - } - } else { - boolean externalAccess = mPreferences.getBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, false); - - if (askPassIsLocal || externalAccess) { - if (debug) Log.d(TAG,"starting actiondispatch"); - - actionDispatch(); - } else { - if (debug) Log.d(TAG, "start showDialogAllowExternalAccess()"); - showDialogAllowExternalAccess(); - } - } - } + } else { + row = new PassEntry(); + } + + if (action.equals(CryptoIntents.ACTION_GET_PASSWORD)) { + if (passExists) { + username = row.plainUsername; + password = row.plainPassword; + } else { + throw new Exception("Could not find password with the unique name: " + clearUniqueName); + } + + // stashing the return values: + callbackIntent.putExtra(CryptoIntents.EXTRA_USERNAME, username); + callbackIntent.putExtra(CryptoIntents.EXTRA_PASSWORD, password); + } else if (action.equals(CryptoIntents.ACTION_SET_PASSWORD)) { + String clearUsername = thisIntent.getStringExtra(CryptoIntents.EXTRA_USERNAME); + String clearPassword = thisIntent.getStringExtra(CryptoIntents.EXTRA_PASSWORD); + if (clearPassword == null) { + throw new Exception("PASSWORD extra must be set."); + } + row.plainUsername = clearUsername == null ? "" : clearUsername; + row.plainPassword = clearPassword; + // since this package is setting the password, it automatically gets access to it: + if (passExists) { //exists already + if (clearUsername.equals("") && clearPassword.equals("")) { + Passwords.deletePassEntry(row.id); + } else { + Passwords.putPassEntry(row); + } + } else {// add a new one + row.plainUniqueName = clearUniqueName; + row.plainDescription = clearUniqueName; //for display purposes + // TODO: Should we send these fields in extras also? If so, probably not using + // the openintents namespace? If another application were to implement a keystore + // they might not want to use these. + row.plainWebsite = ""; + row.plainNote = ""; + + String category = "Application Data"; + CategoryEntry c = Passwords.getCategoryEntryByName(category); + if (c == null) { + c = new CategoryEntry(); + c.plainName = "Application Data"; + c.id = Passwords.putCategoryEntry(c); //doesn't add category if it already exists + } + row.category = c.id; + row.id = 0; // entry is truly new + row.id = Passwords.putPassEntry(row); + } + ArrayList packageAccess = Passwords.getPackageAccess(row.id); + if ((packageAccess == null) || + (!PassEntry.checkPackageAccess(packageAccess, callingPackage))) { + Passwords.addPackageAccess(row.id, callingPackage); + } + + } + return (callbackIntent); + } + + @Override + protected void onPause() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onPause()"); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + startUp(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + /** + * @return + */ + private boolean isIntentLocal() { + String action = getIntent().getAction(); + boolean isLocal = action == null || action.equals(Intent.ACTION_MAIN) || + action.equals(CryptoIntents.ACTION_AUTOLOCK); + if (debug) { + Log.d(TAG, "isLocal=" + isLocal + ", action=" + action); + } + return isLocal; + } + + public void startUp() { + boolean askPassIsLocal = isIntentLocal(); + + if (Master.getMasterKey() == null) { + boolean promptforpassword = getIntent().getBooleanExtra(CryptoIntents.EXTRA_PROMPT, true); + if (debug) { + Log.d(TAG, "Prompt for password: " + promptforpassword); + } + if (promptforpassword) { + if (debug) { + Log.d(TAG, "ask for password"); + } + Intent askPass = new Intent( + getApplicationContext(), + AskPassword.class + ); + + String inputBody = getIntent().getStringExtra(CryptoIntents.EXTRA_TEXT); + + askPass.putExtra(CryptoIntents.EXTRA_TEXT, inputBody); + askPass.putExtra(AskPassword.EXTRA_IS_LOCAL, askPassIsLocal); + //TODO: Is there a way to make sure all the extras are set? + startActivityForResult(askPass, REQUEST_CODE_ASK_PASSWORD); + } else { + if (debug) { + Log.d(TAG, "ask for password"); + } + // Don't prompt but cancel + setResult(RESULT_CANCELED); + finish(); + } + } else { + boolean externalAccess = mPreferences.getBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, false); + + if (askPassIsLocal || externalAccess) { + if (debug) { + Log.d(TAG, "starting actiondispatch"); + } + + actionDispatch(); + } else { + if (debug) { + Log.d(TAG, "start showDialogAllowExternalAccess()"); + } + showDialogAllowExternalAccess(); + } + } + } } diff --git a/Safe/src/org/openintents/safe/Intents.java b/Safe/src/org/openintents/safe/Intents.java index 3c3f77e8..e519f8ac 100644 --- a/Safe/src/org/openintents/safe/Intents.java +++ b/Safe/src/org/openintents/safe/Intents.java @@ -1,10 +1,7 @@ package org.openintents.safe; -import android.content.Context; -import android.content.Intent; import android.net.Uri; - public class Intents { static android.content.Intent createPickFileIntent(String backupPath, int titleResource) { android.content.Intent intent; diff --git a/Safe/src/org/openintents/safe/LogOffActivity.java b/Safe/src/org/openintents/safe/LogOffActivity.java index 2dc7e05b..c55573bc 100644 --- a/Safe/src/org/openintents/safe/LogOffActivity.java +++ b/Safe/src/org/openintents/safe/LogOffActivity.java @@ -1,54 +1,54 @@ package org.openintents.safe; -import org.openintents.safe.service.AutoLockService; -import org.openintents.util.VersionUtils; - import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; -import org.openintents.safe.wrappers.honeycomb.ClipboardManager; - import android.view.View; import android.widget.Button; import android.widget.TextView; +import org.openintents.safe.service.AutoLockService; +import org.openintents.safe.wrappers.honeycomb.ClipboardManager; +import org.openintents.util.VersionUtils; public class LogOffActivity extends Activity { - - private Handler mHandler = new Handler(); - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.log_off); - TextView header = (TextView) findViewById(R.id.logoff_header); - String version = VersionUtils.getVersionNumber(this); - String appName = VersionUtils.getApplicationName(this); - String head = appName + " " + version; - header.setText(head); - Button logoffButton = (Button) findViewById(R.id.logoff_button); - Button gotoPWS = (Button) findViewById(R.id.goto_pws); - - mHandler.postDelayed(mUpdateTimeTask, 0); - - logoffButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { + + private Handler mHandler = new Handler(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.log_off); + TextView header = (TextView) findViewById(R.id.logoff_header); + String version = VersionUtils.getVersionNumber(this); + String appName = VersionUtils.getApplicationName(this); + String head = appName + " " + version; + header.setText(head); + Button logoffButton = (Button) findViewById(R.id.logoff_button); + Button gotoPWS = (Button) findViewById(R.id.goto_pws); + + mHandler.postDelayed(mUpdateTimeTask, 0); + + logoffButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { /* Clear the clipboard, if it contains the last password used */ - ClipboardManager cb = ClipboardManager.newInstance(getApplication()); + ClipboardManager cb = ClipboardManager.newInstance(getApplication()); - if (cb.hasText()) { - String clipboardText = cb.getText().toString(); - if (clipboardText.equals(Safe.last_used_password)) - cb.setText(""); - } + if (cb.hasText()) { + String clipboardText = cb.getText().toString(); + if (clipboardText.equals(Safe.last_used_password)) { + cb.setText(""); + } + } - Intent autoLockIntent = new Intent(getApplicationContext(), AutoLockService.class); - stopService(autoLockIntent); + Intent autoLockIntent = new Intent(getApplicationContext(), AutoLockService.class); + stopService(autoLockIntent); + + CategoryList.setSignedOut(); - CategoryList.setSignedOut(); - /* Intent intent = new Intent(LogOffActivity.this, FrontDoor.class); //intent.setClass (LogOffActivity.this, FrontDoor.class ); @@ -56,38 +56,50 @@ public void onClick(View arg0) { intent.setAction(Intent.ACTION_MAIN); startActivity(intent); */ - finish(); - }}); - - gotoPWS.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - Intent intent = new Intent(LogOffActivity.this, Safe.class); - //intent.setClass (LogOffActivity.this, FrontDoor.class ); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.setAction(Intent.ACTION_MAIN); - startActivity(intent); - finish(); - }}); - } - - - public final Runnable mUpdateTimeTask = new Runnable() { - public void run() { - - TextView time = (TextView) findViewById(R.id.lock_timeout); - long millis = AutoLockService.getTimeRemaining(); - int seconds = (int) (millis / 1000) % 60; - int minutes = (int) (millis / 60000); - - if (seconds < 10) { - time.setText(getString(R.string.lock_timeout, - Integer.toString(minutes) + ":0" + Integer.toString(seconds))); - } else { - time.setText(getString(R.string.lock_timeout, - Integer.toString(minutes) + ":" + Integer.toString(seconds))); - } - - mHandler.postDelayed(this, 1000); - } - }; + finish(); + } + } + ); + + gotoPWS.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + Intent intent = new Intent(LogOffActivity.this, Safe.class); + //intent.setClass (LogOffActivity.this, FrontDoor.class ); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setAction(Intent.ACTION_MAIN); + startActivity(intent); + finish(); + } + } + ); + } + + public final Runnable mUpdateTimeTask = new Runnable() { + public void run() { + + TextView time = (TextView) findViewById(R.id.lock_timeout); + long millis = AutoLockService.getTimeRemaining(); + int seconds = (int) (millis / 1000) % 60; + int minutes = (int) (millis / 60000); + + if (seconds < 10) { + time.setText( + getString( + R.string.lock_timeout, + Integer.toString(minutes) + ":0" + Integer.toString(seconds) + ) + ); + } else { + time.setText( + getString( + R.string.lock_timeout, + Integer.toString(minutes) + ":" + Integer.toString(seconds) + ) + ); + } + + mHandler.postDelayed(this, 1000); + } + }; } diff --git a/Safe/src/org/openintents/safe/OutputStreamData.java b/Safe/src/org/openintents/safe/OutputStreamData.java index 488b78bb..e595ffea 100644 --- a/Safe/src/org/openintents/safe/OutputStreamData.java +++ b/Safe/src/org/openintents/safe/OutputStreamData.java @@ -7,7 +7,6 @@ import java.io.FileOutputStream; import java.io.OutputStream; - public class OutputStreamData { private String filename; private OutputStream stream; diff --git a/Safe/src/org/openintents/safe/PackageAccessEntry.java b/Safe/src/org/openintents/safe/PackageAccessEntry.java index a2723e39..86102f12 100644 --- a/Safe/src/org/openintents/safe/PackageAccessEntry.java +++ b/Safe/src/org/openintents/safe/PackageAccessEntry.java @@ -17,8 +17,8 @@ package org.openintents.safe; public class PackageAccessEntry extends Object { - public boolean needsDecrypt; - public boolean needsEncrypt=true; - public String packageAccess; - public String plainPackageAccess; + public boolean needsDecrypt; + public boolean needsEncrypt = true; + public String packageAccess; + public String plainPackageAccess; } diff --git a/Safe/src/org/openintents/safe/PassEdit.java b/Safe/src/org/openintents/safe/PassEdit.java index 86005d0d..b28876dd 100644 --- a/Safe/src/org/openintents/safe/PassEdit.java +++ b/Safe/src/org/openintents/safe/PassEdit.java @@ -15,10 +15,6 @@ */ package org.openintents.safe; -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.honeycomb.WrapActionBar; - import android.content.Intent; import android.os.Bundle; import android.support.v4.app.FragmentActivity; @@ -27,132 +23,145 @@ import android.view.MenuItem; import android.view.WindowManager; +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.honeycomb.WrapActionBar; + public class PassEdit extends FragmentActivity { - private static final boolean debug = false; - private static final String TAG = "PassEdit"; - - public static final int REQUEST_GEN_PASS = 10; - - public static final int SAVE_PASSWORD_INDEX = Menu.FIRST; - public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 1; - public static final int DISCARD_PASSWORD_INDEX = Menu.FIRST + 2; - public static final int GEN_PASSWORD_INDEX = Menu.FIRST + 3; - - public static final int RESULT_DELETED = RESULT_FIRST_USER; - - private Intent restartTimerIntent = null; - - private MenuItem saveItem; - PassEditFragment fragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (debug) - Log.d(TAG, "onCreate()"); - - // Prevent screen shot shown on recent apps - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, - WindowManager.LayoutParams.FLAG_SECURE); - } - - setContentView(R.layout.pass_edit); - - restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); - - fragment = (PassEditFragment) getSupportFragmentManager() - .findFragmentById(R.id.pass_edit_fragment); - - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (debug) - Log.d(TAG, "onUserInteraction()"); - - if (CategoryList.isSignedIn() == false) { - // startActivity(frontdoor); - } else { - if (restartTimerIntent != null) - sendBroadcast(restartTimerIntent); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - saveItem = menu.add(0, SAVE_PASSWORD_INDEX, 0, R.string.save) - .setIcon(android.R.drawable.ic_menu_save).setShortcut('1', 's'); - fragment.setSaveItem(saveItem); - if (CheckWrappers.mActionBarAvailable) { - WrapActionBar.showIfRoom(saveItem); - saveItem.setVisible(!fragment.allFieldsEmpty()); - } - menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete).setIcon( - android.R.drawable.ic_menu_delete); - menu.add(0, DISCARD_PASSWORD_INDEX, 0, R.string.discard_changes) - .setIcon(android.R.drawable.ic_notification_clear_all); - menu.add(0, GEN_PASSWORD_INDEX, 0, "Generate") - .setIcon(android.R.drawable.ic_menu_set_as) - .setShortcut('4', 'g'); - - return super.onCreateOptionsMenu(menu); - } - - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - fragment.setDiscardEntry(true); - finish(); - break; - case SAVE_PASSWORD_INDEX: - fragment.savePassword(); - finish(); - break; - case DEL_PASSWORD_INDEX: - fragment.deletePassword(); - break; - case DISCARD_PASSWORD_INDEX: - fragment.setDiscardEntry(true); - finish(); - break; - case GEN_PASSWORD_INDEX: - Intent i = new Intent(getApplicationContext(), PassGen.class); - startActivityForResult(i, REQUEST_GEN_PASS); - } - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - if (!CheckWrappers.mActionBarAvailable) { - menu.findItem(SAVE_PASSWORD_INDEX).setEnabled( - !fragment.allFieldsEmpty()); - } - return super.onMenuOpened(featureId, menu); - } - - /** - * - */ - @Override - public void onActivityResult(int requestCode, int resultCode, Intent i) { - super.onActivityResult(requestCode, resultCode, i); - - if (requestCode == REQUEST_GEN_PASS) { - if (resultCode == PassGen.CHANGE_ENTRY_RESULT) { - String new_pass = i.getStringExtra(PassGen.NEW_PASS_KEY); - if (debug) Log.d(TAG, new_pass); - fragment.passwordText.setText(new_pass); - fragment.pass_gen_ret = true; - } - } - } + private static final boolean debug = false; + private static final String TAG = "PassEdit"; + + public static final int REQUEST_GEN_PASS = 10; + + public static final int SAVE_PASSWORD_INDEX = Menu.FIRST; + public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 1; + public static final int DISCARD_PASSWORD_INDEX = Menu.FIRST + 2; + public static final int GEN_PASSWORD_INDEX = Menu.FIRST + 3; + + public static final int RESULT_DELETED = RESULT_FIRST_USER; + + private Intent restartTimerIntent = null; + + private MenuItem saveItem; + PassEditFragment fragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (debug) { + Log.d(TAG, "onCreate()"); + } + + // Prevent screen shot shown on recent apps + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + getWindow().setFlags( + WindowManager.LayoutParams.FLAG_SECURE, + WindowManager.LayoutParams.FLAG_SECURE + ); + } + + setContentView(R.layout.pass_edit); + + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + fragment = (PassEditFragment) getSupportFragmentManager() + .findFragmentById(R.id.pass_edit_fragment); + + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { + // startActivity(frontdoor); + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + saveItem = menu.add(0, SAVE_PASSWORD_INDEX, 0, R.string.save) + .setIcon(android.R.drawable.ic_menu_save).setShortcut('1', 's'); + fragment.setSaveItem(saveItem); + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar.showIfRoom(saveItem); + saveItem.setVisible(!fragment.allFieldsEmpty()); + } + menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete).setIcon( + android.R.drawable.ic_menu_delete + ); + menu.add(0, DISCARD_PASSWORD_INDEX, 0, R.string.discard_changes) + .setIcon(android.R.drawable.ic_notification_clear_all); + menu.add(0, GEN_PASSWORD_INDEX, 0, "Generate") + .setIcon(android.R.drawable.ic_menu_set_as) + .setShortcut('4', 'g'); + + return super.onCreateOptionsMenu(menu); + } + + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + fragment.setDiscardEntry(true); + finish(); + break; + case SAVE_PASSWORD_INDEX: + fragment.savePassword(); + finish(); + break; + case DEL_PASSWORD_INDEX: + fragment.deletePassword(); + break; + case DISCARD_PASSWORD_INDEX: + fragment.setDiscardEntry(true); + finish(); + break; + case GEN_PASSWORD_INDEX: + Intent i = new Intent(getApplicationContext(), PassGen.class); + startActivityForResult(i, REQUEST_GEN_PASS); + } + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + if (!CheckWrappers.mActionBarAvailable) { + menu.findItem(SAVE_PASSWORD_INDEX).setEnabled( + !fragment.allFieldsEmpty() + ); + } + return super.onMenuOpened(featureId, menu); + } + + /** + * + */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + + if (requestCode == REQUEST_GEN_PASS) { + if (resultCode == PassGen.CHANGE_ENTRY_RESULT) { + String new_pass = i.getStringExtra(PassGen.NEW_PASS_KEY); + if (debug) { + Log.d(TAG, new_pass); + } + fragment.passwordText.setText(new_pass); + fragment.pass_gen_ret = true; + } + } + } } diff --git a/Safe/src/org/openintents/safe/PassEditFragment.java b/Safe/src/org/openintents/safe/PassEditFragment.java index f3e64255..569bdb88 100644 --- a/Safe/src/org/openintents/safe/PassEditFragment.java +++ b/Safe/src/org/openintents/safe/PassEditFragment.java @@ -15,11 +15,6 @@ */ package org.openintents.safe; -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.honeycomb.ClipboardManager; -import org.openintents.safe.wrappers.honeycomb.WrapActionBar; - import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -44,388 +39,421 @@ import android.widget.EditText; import android.widget.Toast; +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.honeycomb.ClipboardManager; +import org.openintents.safe.wrappers.honeycomb.WrapActionBar; + public class PassEditFragment extends Fragment { - private static final String TAG = "PassEditFragment"; - private static final boolean debug = false; - public static final int REQUEST_GEN_PASS = 10; - - public static final int SAVE_PASSWORD_INDEX = Menu.FIRST; - public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 1; - public static final int DISCARD_PASSWORD_INDEX = Menu.FIRST + 2; - public static final int GEN_PASSWORD_INDEX = Menu.FIRST + 3; - - public static final int RESULT_DELETED = Activity.RESULT_FIRST_USER; - - private EditText descriptionText; - public EditText passwordText; - private EditText usernameText; - private EditText websiteText; - private EditText noteText; - private Long RowId; - private Long CategoryId; - public boolean pass_gen_ret = false; - private boolean discardEntry = false; - public static boolean entryEdited = false; - boolean populated = false; - private MenuItem saveItem = null; - - Intent frontdoor; - private Intent restartTimerIntent = null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals( - CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) - Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - if (debug) - Log.d(TAG, "onCreateView()"); - - ViewGroup root = (ViewGroup) inflater.inflate( - R.layout.pass_edit_fragment, null); - - RowId = savedInstanceState != null ? savedInstanceState - .getLong(PassList.KEY_ID) : null; - if (RowId == null) { - Bundle extras = getActivity().getIntent().getExtras(); - RowId = extras != null ? extras.getLong(PassList.KEY_ID) : null; - } - CategoryId = savedInstanceState != null ? savedInstanceState - .getLong(PassList.KEY_CATEGORY_ID) : null; - if (CategoryId == null) { - Bundle extras = getActivity().getIntent().getExtras(); - CategoryId = extras != null ? extras - .getLong(PassList.KEY_CATEGORY_ID) : null; - } - if (debug) - Log.d(TAG, "RowId=" + RowId); - if (debug) - Log.d(TAG, "CategoryId=" + CategoryId); - - if ((CategoryId == null) || (CategoryId < 1)) { - // invalid Category - getActivity().finish(); - return root; - } - - frontdoor = new Intent(getActivity(), Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); - - String title = getResources().getString(R.string.app_name) + " - " - + getResources().getString(R.string.edit_entry); - getActivity().setTitle(title); - - descriptionText = (EditText) root.findViewById(R.id.description); - descriptionText.requestFocus(); - passwordText = (EditText) root.findViewById(R.id.password); - usernameText = (EditText) root.findViewById(R.id.username); - noteText = (EditText) root.findViewById(R.id.note); - websiteText = (EditText) root.findViewById(R.id.website); - - Button goButton = (Button) root.findViewById(R.id.go); - - entryEdited = false; - - goButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - - String link = websiteText.getText().toString(); - if (link == null || link.equals("") || link.equals("http://")) { - Toast.makeText(getActivity(), - getString(R.string.invalid_url), Toast.LENGTH_SHORT) - .show(); - return; - } - - Toast.makeText( - getActivity(), - getString(R.string.password) + " " - + getString(R.string.copied_to_clipboard), - Toast.LENGTH_SHORT).show(); - - ClipboardManager cb = ClipboardManager - .newInstance(getActivity().getApplication()); - cb.setText(passwordText.getText().toString()); - - Intent i = new Intent(Intent.ACTION_VIEW); - - Uri u = Uri.parse(link); - i.setData(u); - try { - startActivity(i); - } catch (ActivityNotFoundException e) { - // Let's try to catch the most common mistake: omitting - // http: - u = Uri.parse("http://" + link); - i.setData(u); - try { - startActivity(i); - } catch (ActivityNotFoundException e2) { - Toast.makeText(getActivity(), R.string.invalid_website, - Toast.LENGTH_SHORT).show(); - } - } - } - }); - // restoreMe(); - - if (CheckWrappers.mActionBarAvailable) { - WrapActionBar bar = new WrapActionBar(getActivity()); - bar.setDisplayHomeAsUpEnabled(true); - - // if Action Bar is available, save button needs to be updated more - // often - TextWatcher textWatcher = new TextWatcher() { - public void afterTextChanged(Editable s) { - } - - public void beforeTextChanged(CharSequence s, int start, - int count, int after) { - } - - public void onTextChanged(CharSequence s, int start, - int before, int count) { - if (saveItem != null) { - saveItem.setVisible(!allFieldsEmpty()); - } - } - }; - descriptionText.addTextChangedListener(textWatcher); - passwordText.addTextChangedListener(textWatcher); - usernameText.addTextChangedListener(textWatcher); - noteText.addTextChangedListener(textWatcher); - websiteText.addTextChangedListener(textWatcher); - } - - getActivity().sendBroadcast(restartTimerIntent); - return root; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - if (debug) - Log.d(TAG, "onSaveInstanceState()"); - if (RowId != null) { - outState.putLong(PassList.KEY_ID, RowId); - } else { - outState.putLong(PassList.KEY_ID, -1); - } - outState.putLong(PassList.KEY_CATEGORY_ID, CategoryId); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - if (debug) - Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")"); - - if (savedInstanceState != null) { - if (savedInstanceState.containsKey(PassList.KEY_ID)) { - RowId = savedInstanceState.getLong(PassList.KEY_ID); - } - if (savedInstanceState.containsKey(PassList.KEY_CATEGORY_ID)) { - CategoryId = savedInstanceState - .getLong(PassList.KEY_CATEGORY_ID); - } - populated = true; - } - } - - @Override - public void onPause() { - super.onPause(); - if (debug) - Log.d(TAG, "onPause()"); - - if (getActivity().isFinishing() && discardEntry == false && allFieldsEmpty() == false) { - savePassword(); - } - try { - getActivity().unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - // if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - public void setDiscardEntry(boolean discard) { - discardEntry=discard; - } - - public void setSaveItem(MenuItem save) { - saveItem=save; - } - - @Override - public void onResume() { - super.onResume(); - - if (debug) - Log.d(TAG, "onResume()"); - - if (CategoryList.isSignedIn() == false) { - // if (Passwords.isCryptoInitialized()) { - // saveState(); - // } - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter( - CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - getActivity().registerReceiver(mIntentReceiver, filter); - - Passwords.Initialize(getActivity()); - - populateFields(); - } - - private void saveState() { - PassEntry entry = new PassEntry(); - - entry.category = CategoryId; - entry.plainDescription = descriptionText.getText().toString(); - entry.plainWebsite = websiteText.getText().toString(); - entry.plainUsername = usernameText.getText().toString(); - entry.plainPassword = passwordText.getText().toString(); - entry.plainNote = noteText.getText().toString(); - - entryEdited = true; - - if (RowId == null || RowId == -1) { - entry.id = 0; // brand new entry - RowId = Passwords.putPassEntry(entry); - if (RowId == -1) { - Toast.makeText(getActivity(), R.string.entry_save_error, - Toast.LENGTH_LONG).show(); - return; - } - } else { - entry.id = RowId; - PassEntry storedEntry = Passwords.getPassEntry(RowId, true, false); - // update fields that aren't set in the UI: - entry.uniqueName = storedEntry.uniqueName; - long success = Passwords.putPassEntry(entry); - if (success == -1) { - Toast.makeText(getActivity(), R.string.entry_save_error, - Toast.LENGTH_LONG).show(); - return; - } - } - Toast.makeText(getActivity(), R.string.entry_saved, Toast.LENGTH_SHORT) - .show(); - } - - /** - * Returns true if all fields are empty. - */ - public boolean allFieldsEmpty() { - return (descriptionText.getText().toString().trim().equals("") - && websiteText.getText().toString().trim().equals("") - && usernameText.getText().toString().trim().equals("") - && passwordText.getText().toString().trim().equals("") && noteText - .getText().toString().trim().equals("")); - } - - /** - * Save the password entry and finish the activity. - */ - public void savePassword() { - saveState(); - getActivity().setResult(Activity.RESULT_OK); - } - - /** - * Prompt the user with a dialog asking them if they really want to delete - * the password. - */ - public void deletePassword() { - Dialog about = new AlertDialog.Builder(getActivity()) - .setIcon(R.drawable.passicon) - .setTitle(R.string.dialog_delete_password_title) - .setPositiveButton(R.string.yes, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - deletePassword2(); - } - }) - .setNegativeButton(R.string.no, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - // do nothing - } - }).setMessage(R.string.dialog_delete_password_msg) - .create(); - about.show(); - } - - /** - * Follow up for the Delete Password dialog. If we have a RowId then delete - * the password, otherwise just finish this Activity. - */ - public void deletePassword2() { - if ((RowId != null) && (RowId > 0)) { - delPassword(RowId); - } else { - // user specified to delete a new entry - // so simply exit out - getActivity().finish(); - } - } - - /** - * Delete the password entry from the database given the row id within the - * database. - * - * @param Id - */ - private void delPassword(long Id) { - Passwords.deletePassEntry(Id); - discardEntry = true; - getActivity().setResult(RESULT_DELETED); - getActivity().finish(); - } - - /** - * - */ - private void populateFields() { - if (debug) - Log.d(TAG, "populateFields()"); - if (pass_gen_ret == true) { - pass_gen_ret = false; - return; - } - if (debug) - Log.d(TAG, "populateFields: populated=" + populated); - if (populated) { - return; - } - if ((RowId != null) && (RowId != -1)) { - PassEntry passEntry = Passwords.getPassEntry(RowId, true, false); - if (passEntry != null) { - descriptionText.setText(passEntry.plainDescription); - websiteText.setText(passEntry.plainWebsite); - usernameText.setText(passEntry.plainUsername); - passwordText.setText(passEntry.plainPassword); - noteText.setText(passEntry.plainNote); - } - } - populated = true; - } + private static final String TAG = "PassEditFragment"; + private static final boolean debug = false; + public static final int REQUEST_GEN_PASS = 10; + + public static final int SAVE_PASSWORD_INDEX = Menu.FIRST; + public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 1; + public static final int DISCARD_PASSWORD_INDEX = Menu.FIRST + 2; + public static final int GEN_PASSWORD_INDEX = Menu.FIRST + 3; + + public static final int RESULT_DELETED = Activity.RESULT_FIRST_USER; + + private EditText descriptionText; + public EditText passwordText; + private EditText usernameText; + private EditText websiteText; + private EditText noteText; + private Long RowId; + private Long CategoryId; + public boolean pass_gen_ret = false; + private boolean discardEntry = false; + public static boolean entryEdited = false; + boolean populated = false; + private MenuItem saveItem = null; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals( + CryptoIntents.ACTION_CRYPTO_LOGGED_OUT + )) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + if (debug) { + Log.d(TAG, "onCreateView()"); + } + + ViewGroup root = (ViewGroup) inflater.inflate( + R.layout.pass_edit_fragment, null + ); + + RowId = savedInstanceState != null ? savedInstanceState + .getLong(PassList.KEY_ID) : null; + if (RowId == null) { + Bundle extras = getActivity().getIntent().getExtras(); + RowId = extras != null ? extras.getLong(PassList.KEY_ID) : null; + } + CategoryId = savedInstanceState != null ? savedInstanceState + .getLong(PassList.KEY_CATEGORY_ID) : null; + if (CategoryId == null) { + Bundle extras = getActivity().getIntent().getExtras(); + CategoryId = extras != null ? extras + .getLong(PassList.KEY_CATEGORY_ID) : null; + } + if (debug) { + Log.d(TAG, "RowId=" + RowId); + } + if (debug) { + Log.d(TAG, "CategoryId=" + CategoryId); + } + + if ((CategoryId == null) || (CategoryId < 1)) { + // invalid Category + getActivity().finish(); + return root; + } + + frontdoor = new Intent(getActivity(), Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.edit_entry); + getActivity().setTitle(title); + + descriptionText = (EditText) root.findViewById(R.id.description); + descriptionText.requestFocus(); + passwordText = (EditText) root.findViewById(R.id.password); + usernameText = (EditText) root.findViewById(R.id.username); + noteText = (EditText) root.findViewById(R.id.note); + websiteText = (EditText) root.findViewById(R.id.website); + + Button goButton = (Button) root.findViewById(R.id.go); + + entryEdited = false; + + goButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + + String link = websiteText.getText().toString(); + if (link == null || link.equals("") || link.equals("http://")) { + Toast.makeText( + getActivity(), + getString(R.string.invalid_url), Toast.LENGTH_SHORT + ) + .show(); + return; + } + + Toast.makeText( + getActivity(), + getString(R.string.password) + " " + + getString(R.string.copied_to_clipboard), + Toast.LENGTH_SHORT + ).show(); + + ClipboardManager cb = ClipboardManager + .newInstance(getActivity().getApplication()); + cb.setText(passwordText.getText().toString()); + + Intent i = new Intent(Intent.ACTION_VIEW); + + Uri u = Uri.parse(link); + i.setData(u); + try { + startActivity(i); + } catch (ActivityNotFoundException e) { + // Let's try to catch the most common mistake: omitting + // http: + u = Uri.parse("http://" + link); + i.setData(u); + try { + startActivity(i); + } catch (ActivityNotFoundException e2) { + Toast.makeText( + getActivity(), R.string.invalid_website, + Toast.LENGTH_SHORT + ).show(); + } + } + } + } + ); + // restoreMe(); + + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar bar = new WrapActionBar(getActivity()); + bar.setDisplayHomeAsUpEnabled(true); + + // if Action Bar is available, save button needs to be updated more + // often + TextWatcher textWatcher = new TextWatcher() { + public void afterTextChanged(Editable s) { + } + + public void beforeTextChanged(CharSequence s, int start, + int count, int after) { + } + + public void onTextChanged(CharSequence s, int start, + int before, int count) { + if (saveItem != null) { + saveItem.setVisible(!allFieldsEmpty()); + } + } + }; + descriptionText.addTextChangedListener(textWatcher); + passwordText.addTextChangedListener(textWatcher); + usernameText.addTextChangedListener(textWatcher); + noteText.addTextChangedListener(textWatcher); + websiteText.addTextChangedListener(textWatcher); + } + + getActivity().sendBroadcast(restartTimerIntent); + return root; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + if (debug) { + Log.d(TAG, "onSaveInstanceState()"); + } + if (RowId != null) { + outState.putLong(PassList.KEY_ID, RowId); + } else { + outState.putLong(PassList.KEY_ID, -1); + } + outState.putLong(PassList.KEY_CATEGORY_ID, CategoryId); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + if (debug) { + Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")"); + } + + if (savedInstanceState != null) { + if (savedInstanceState.containsKey(PassList.KEY_ID)) { + RowId = savedInstanceState.getLong(PassList.KEY_ID); + } + if (savedInstanceState.containsKey(PassList.KEY_CATEGORY_ID)) { + CategoryId = savedInstanceState + .getLong(PassList.KEY_CATEGORY_ID); + } + populated = true; + } + } + + @Override + public void onPause() { + super.onPause(); + if (debug) { + Log.d(TAG, "onPause()"); + } + + if (getActivity().isFinishing() && discardEntry == false && allFieldsEmpty() == false) { + savePassword(); + } + try { + getActivity().unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + // if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + public void setDiscardEntry(boolean discard) { + discardEntry = discard; + } + + public void setSaveItem(MenuItem save) { + saveItem = save; + } + + @Override + public void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + + if (CategoryList.isSignedIn() == false) { + // if (Passwords.isCryptoInitialized()) { + // saveState(); + // } + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter( + CryptoIntents.ACTION_CRYPTO_LOGGED_OUT + ); + getActivity().registerReceiver(mIntentReceiver, filter); + + Passwords.Initialize(getActivity()); + + populateFields(); + } + + private void saveState() { + PassEntry entry = new PassEntry(); + + entry.category = CategoryId; + entry.plainDescription = descriptionText.getText().toString(); + entry.plainWebsite = websiteText.getText().toString(); + entry.plainUsername = usernameText.getText().toString(); + entry.plainPassword = passwordText.getText().toString(); + entry.plainNote = noteText.getText().toString(); + + entryEdited = true; + + if (RowId == null || RowId == -1) { + entry.id = 0; // brand new entry + RowId = Passwords.putPassEntry(entry); + if (RowId == -1) { + Toast.makeText( + getActivity(), R.string.entry_save_error, + Toast.LENGTH_LONG + ).show(); + return; + } + } else { + entry.id = RowId; + PassEntry storedEntry = Passwords.getPassEntry(RowId, true, false); + // update fields that aren't set in the UI: + entry.uniqueName = storedEntry.uniqueName; + long success = Passwords.putPassEntry(entry); + if (success == -1) { + Toast.makeText( + getActivity(), R.string.entry_save_error, + Toast.LENGTH_LONG + ).show(); + return; + } + } + Toast.makeText(getActivity(), R.string.entry_saved, Toast.LENGTH_SHORT) + .show(); + } + + /** + * Returns true if all fields are empty. + */ + public boolean allFieldsEmpty() { + return (descriptionText.getText().toString().trim().equals("") + && websiteText.getText().toString().trim().equals("") + && usernameText.getText().toString().trim().equals("") + && passwordText.getText().toString().trim().equals("") && noteText + .getText().toString().trim().equals("")); + } + + /** + * Save the password entry and finish the activity. + */ + public void savePassword() { + saveState(); + getActivity().setResult(Activity.RESULT_OK); + } + + /** + * Prompt the user with a dialog asking them if they really want to delete + * the password. + */ + public void deletePassword() { + Dialog about = new AlertDialog.Builder(getActivity()) + .setIcon(R.drawable.passicon) + .setTitle(R.string.dialog_delete_password_title) + .setPositiveButton( + R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + deletePassword2(); + } + } + ) + .setNegativeButton( + R.string.no, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + // do nothing + } + } + ).setMessage(R.string.dialog_delete_password_msg) + .create(); + about.show(); + } + + /** + * Follow up for the Delete Password dialog. If we have a RowId then delete + * the password, otherwise just finish this Activity. + */ + public void deletePassword2() { + if ((RowId != null) && (RowId > 0)) { + delPassword(RowId); + } else { + // user specified to delete a new entry + // so simply exit out + getActivity().finish(); + } + } + + /** + * Delete the password entry from the database given the row id within the + * database. + * + * @param Id + */ + private void delPassword(long Id) { + Passwords.deletePassEntry(Id); + discardEntry = true; + getActivity().setResult(RESULT_DELETED); + getActivity().finish(); + } + + /** + * + */ + private void populateFields() { + if (debug) { + Log.d(TAG, "populateFields()"); + } + if (pass_gen_ret == true) { + pass_gen_ret = false; + return; + } + if (debug) { + Log.d(TAG, "populateFields: populated=" + populated); + } + if (populated) { + return; + } + if ((RowId != null) && (RowId != -1)) { + PassEntry passEntry = Passwords.getPassEntry(RowId, true, false); + if (passEntry != null) { + descriptionText.setText(passEntry.plainDescription); + websiteText.setText(passEntry.plainWebsite); + usernameText.setText(passEntry.plainUsername); + passwordText.setText(passEntry.plainPassword); + noteText.setText(passEntry.plainNote); + } + } + populated = true; + } } diff --git a/Safe/src/org/openintents/safe/PassEntry.java b/Safe/src/org/openintents/safe/PassEntry.java index 7bf63113..56bdf957 100644 --- a/Safe/src/org/openintents/safe/PassEntry.java +++ b/Safe/src/org/openintents/safe/PassEntry.java @@ -19,32 +19,31 @@ import java.util.ArrayList; /** - * * @author Steven Osborn - http://steven.bitsetters.com */ public class PassEntry extends Object { - public long id=-1; - public boolean needsDecryptDescription; - public boolean needsDecrypt; - public boolean needsEncrypt=true; - public String password; - public long category; - public String categoryName; - public String description; - public String username; - public String website; - public String uniqueName; - public ArrayList packageAccess; - public String note; - public String plainPassword; - public String plainDescription; - public String plainUsername; - public String plainWebsite; - public String plainNote; - public String plainUniqueName; - public String lastEdited; + public long id = -1; + public boolean needsDecryptDescription; + public boolean needsDecrypt; + public boolean needsEncrypt = true; + public String password; + public long category; + public String categoryName; + public String description; + public String username; + public String website; + public String uniqueName; + public ArrayList packageAccess; + public String note; + public String plainPassword; + public String plainDescription; + public String plainUsername; + public String plainWebsite; + public String plainNote; + public String plainUniqueName; + public String lastEdited; - public static boolean checkPackageAccess (ArrayList packageAccess, String packageName) { - return (packageAccess.contains(packageName)); - } -} \ No newline at end of file + public static boolean checkPackageAccess(ArrayList packageAccess, String packageName) { + return (packageAccess.contains(packageName)); + } +} diff --git a/Safe/src/org/openintents/safe/PassGen.java b/Safe/src/org/openintents/safe/PassGen.java index e4a62144..150a3163 100644 --- a/Safe/src/org/openintents/safe/PassGen.java +++ b/Safe/src/org/openintents/safe/PassGen.java @@ -16,260 +16,267 @@ */ package org.openintents.safe; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; - -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.honeycomb.WrapActionBar; - import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; -import org.openintents.safe.wrappers.honeycomb.ClipboardManager; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; +import android.view.View.OnFocusChangeListener; import android.view.View.OnKeyListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; -import android.widget.EditText; import android.widget.CompoundButton.OnCheckedChangeListener; -import android.view.View.OnFocusChangeListener; +import android.widget.EditText; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.honeycomb.ClipboardManager; +import org.openintents.safe.wrappers.honeycomb.WrapActionBar; /** * PassGen Activity - * + * * @author Steven Osborn - http://steven.bitsetters.com */ public class PassGen extends Activity { - private static boolean debug = false; - private static String TAG = "PassGen"; - - public static final int CHANGE_ENTRY_RESULT = 2; - public static final String NEW_PASS_KEY="new_pass"; - - EditText pass_view; - EditText pass_len; - CheckBox pass_upper; - CheckBox pass_lower; - CheckBox pass_num; - CheckBox pass_symbol; - String charset = ""; - - Button copy_clip; - Button copy_entry; - Button cancel; - - Intent frontdoor; - private Intent restartTimerIntent=null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - private final OnClickListener update_click = new OnClickListener() { - public void onClick(View v) { - genPassword(); - } - }; - private final OnCheckedChangeListener update_checked = new OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - genPassword(); - } - }; - private final OnKeyListener update_key = new OnKeyListener() { - public boolean onKey(View v, int keyCode, KeyEvent event) { - genPassword(); - return false; - } - - }; - private final OnFocusChangeListener update_focus = new OnFocusChangeListener() { - public void onFocusChange(View v, boolean hasFocus) { - genPassword(); - } - }; - - private final OnClickListener cancel_listener = new OnClickListener() { - public void onClick(View v) { - finish(); - } - }; - - private final OnClickListener copy_clip_listener = new OnClickListener() { - public void onClick(View v) { - ClipboardManager cb = ClipboardManager.newInstance(getApplication()); - cb.setText(pass_view.getText().toString()); - finish(); - } - }; - - private final OnClickListener copy_entry_listener = new OnClickListener() { - public void onClick(View v) { - getIntent().putExtra(PassGen.NEW_PASS_KEY, pass_view.getText().toString()); - setResult(CHANGE_ENTRY_RESULT, getIntent()); - finish(); - } - }; - - - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent (CryptoIntents.ACTION_RESTART_TIMER); - - setContentView(R.layout.pass_gen); - - String title = getString(R.string.app_name) + " - " + - getString(R.string.generate_password); - setTitle(title); - - pass_view = (EditText) findViewById(R.id.pass_view); - pass_len = (EditText) findViewById(R.id.pass_length); - pass_upper = (CheckBox) findViewById(R.id.pass_upper); - pass_lower = (CheckBox) findViewById(R.id.pass_lower); - pass_num = (CheckBox) findViewById(R.id.pass_num); - pass_symbol = (CheckBox) findViewById(R.id.pass_symbol); - - pass_view.setOnClickListener(update_click); - pass_len.setOnKeyListener(update_key); - pass_len.setOnFocusChangeListener(update_focus); - pass_upper.setOnCheckedChangeListener(update_checked); - pass_lower.setOnCheckedChangeListener(update_checked); - pass_num.setOnCheckedChangeListener(update_checked); - pass_symbol.setOnCheckedChangeListener(update_checked); - - copy_clip = (Button) findViewById(R.id.copy_clip); - copy_entry = (Button) findViewById(R.id.copy_entry); - cancel = (Button) findViewById(R.id.cancel); - - copy_clip.setOnClickListener(copy_clip_listener); - copy_entry.setOnClickListener(copy_entry_listener); - cancel.setOnClickListener(cancel_listener); - - if(CheckWrappers.mActionBarAvailable){ - WrapActionBar bar = new WrapActionBar(this); - bar.setDisplayHomeAsUpEnabled(true); - } - } - - /** - * - */ - protected void genPassword() { - charset = ""; - StringBuilder pass = new StringBuilder(); - if(pass_upper.isChecked()) { - charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - } - if(pass_lower.isChecked()) { - charset += "abcdefghijklmnopqrstuvwxyz"; - } - if(pass_num.isChecked()) { - charset += "0123456789"; - } - if(pass_symbol.isChecked()) { - charset += "!@#$%^&*"; - } - - if (charset.length() == 0) { - return; - } - int len=0; - try { - len = Integer.parseInt(pass_len.getText().toString()); - } catch (NumberFormatException e) { - e.printStackTrace(); - } - - SecureRandom generator = null; - try { - generator = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - for(int i=0;i + * This is the main activity for PasswordSafe all other activities are + * spawned as sub-activities of this one. The basic application * skeleton was based on google's notepad example. - * + * * @author Steven Osborn - http://steven.bitsetters.com */ public class PassList extends ListActivity { - private static final boolean debug = false; - private static final String TAG = "PassList"; - - // Menu Item order - public static final int VIEW_PASSWORD_INDEX = Menu.FIRST; - public static final int EDIT_PASSWORD_INDEX = Menu.FIRST + 1; - public static final int ADD_PASSWORD_INDEX = Menu.FIRST + 2; - public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 3; - public static final int MOVE_PASSWORD_INDEX = Menu.FIRST + 4; - - public static final int REQUEST_VIEW_PASSWORD = 1; - public static final int REQUEST_EDIT_PASSWORD = 2; - public static final int REQUEST_ADD_PASSWORD = 3; - public static final int REQUEST_MOVE_PASSWORD = 4; - - protected static final int MSG_UPDATE_LIST = 0x101; - - public static final String KEY_ID = "id"; // Intent keys - public static final String KEY_CATEGORY_ID = "categoryId"; // Intent keys - public static final String KEY_ROWIDS = "rowids"; - public static final String KEY_LIST_POSITION = "position"; - - private Long CategoryId=null; - - Intent frontdoor; - private Intent restartTimerIntent=null; - - private static fillerTask taskFiller = null; - private ProgressDialog decryptProgress = null; - - private List rows=null; - private int lastPosition=0; - - // passDescriptions is updated by the background thread - List passDescriptions=new ArrayList(); - // passDescriptions4Adapter must only be modified by the UI thread - List passDescriptions4Adapter=new ArrayList(); - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - if (debug) Log.d(TAG,"onCreate("+icicle+")"); - - CategoryId = icicle != null ? icicle.getLong(CategoryList.KEY_ID) : null; - if (CategoryId == null) { - Bundle extras = getIntent().getExtras(); - CategoryId = extras != null ? extras.getLong(CategoryList.KEY_ID) : null; - } - if (debug) Log.d(TAG,"CategoryId="+CategoryId); - if ((CategoryId==null) || (CategoryId<1)) { - finish(); // no valid category - return; - } - - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent (CryptoIntents.ACTION_RESTART_TIMER); - - setContentView(R.layout.pass_list); - - final ListView list = getListView(); - list.setFocusable(true); - list.setOnCreateContextMenuListener(this); - list.setTextFilterEnabled(true); - registerForContextMenu(list); - - if(CheckWrappers.mActionBarAvailable){ - WrapActionBar bar = new WrapActionBar(this); - bar.setDisplayHomeAsUpEnabled(true); - } - - sendBroadcast (restartTimerIntent); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - if (debug) Log.d(TAG,"onSaveInstanceState(): CategoryId="+CategoryId); - // remember which Category we're looking at - if (CategoryId != null) { - outState.putLong(CategoryList.KEY_ID, CategoryId); - } else { - outState.putLong(CategoryList.KEY_ID, -1); - } - } - - @Override - protected void onPause() { - super.onPause(); - - if (debug) Log.d(TAG,"onPause()"); - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - if (taskFiller != null) { - decryptProgress.dismiss(); - taskFiller.setActivity(null); - } - - } - - @Override - protected void onResume() { - super.onResume(); - - if (debug) Log.d(TAG,"onResume()"); - - if (CategoryList.isSignedIn()==false) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - - Passwords.Initialize(this); - - String categoryName=Passwords.getCategoryEntry(CategoryId).plainName; - String title = getResources().getString(R.string.app_name) + " - " + - getResources().getString(R.string.passwords) + " -" + - categoryName; - setTitle(title); - - if (taskFiller!=null) { - // taskFiller still running - taskFiller.setActivity(this); - startDecryptProgressDialog(); - } - ListAdapter la=getListAdapter(); - if (la!=null) { - if (debug) Log.d(TAG,"onResume: count="+la.getCount()); - } else { - if (debug) Log.d(TAG,"onResume: no list"); - /* HACK to make textFilter work!!! + private static final boolean debug = false; + private static final String TAG = "PassList"; + + // Menu Item order + public static final int VIEW_PASSWORD_INDEX = Menu.FIRST; + public static final int EDIT_PASSWORD_INDEX = Menu.FIRST + 1; + public static final int ADD_PASSWORD_INDEX = Menu.FIRST + 2; + public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 3; + public static final int MOVE_PASSWORD_INDEX = Menu.FIRST + 4; + + public static final int REQUEST_VIEW_PASSWORD = 1; + public static final int REQUEST_EDIT_PASSWORD = 2; + public static final int REQUEST_ADD_PASSWORD = 3; + public static final int REQUEST_MOVE_PASSWORD = 4; + + protected static final int MSG_UPDATE_LIST = 0x101; + + public static final String KEY_ID = "id"; // Intent keys + public static final String KEY_CATEGORY_ID = "categoryId"; // Intent keys + public static final String KEY_ROWIDS = "rowids"; + public static final String KEY_LIST_POSITION = "position"; + + private Long CategoryId = null; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + private static fillerTask taskFiller = null; + private ProgressDialog decryptProgress = null; + + private List rows = null; + private int lastPosition = 0; + + // passDescriptions is updated by the background thread + List passDescriptions = new ArrayList(); + // passDescriptions4Adapter must only be modified by the UI thread + List passDescriptions4Adapter = new ArrayList(); + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + if (debug) { + Log.d(TAG, "onCreate(" + icicle + ")"); + } + + CategoryId = icicle != null ? icicle.getLong(CategoryList.KEY_ID) : null; + if (CategoryId == null) { + Bundle extras = getIntent().getExtras(); + CategoryId = extras != null ? extras.getLong(CategoryList.KEY_ID) : null; + } + if (debug) { + Log.d(TAG, "CategoryId=" + CategoryId); + } + if ((CategoryId == null) || (CategoryId < 1)) { + finish(); // no valid category + return; + } + + frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + setContentView(R.layout.pass_list); + + final ListView list = getListView(); + list.setFocusable(true); + list.setOnCreateContextMenuListener(this); + list.setTextFilterEnabled(true); + registerForContextMenu(list); + + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar bar = new WrapActionBar(this); + bar.setDisplayHomeAsUpEnabled(true); + } + + sendBroadcast(restartTimerIntent); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + if (debug) { + Log.d(TAG, "onSaveInstanceState(): CategoryId=" + CategoryId); + } + // remember which Category we're looking at + if (CategoryId != null) { + outState.putLong(CategoryList.KEY_ID, CategoryId); + } else { + outState.putLong(CategoryList.KEY_ID, -1); + } + } + + @Override + protected void onPause() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onPause()"); + } + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + if (taskFiller != null) { + decryptProgress.dismiss(); + taskFiller.setActivity(null); + } + + } + + @Override + protected void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + + if (CategoryList.isSignedIn() == false) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + + Passwords.Initialize(this); + + String categoryName = Passwords.getCategoryEntry(CategoryId).plainName; + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.passwords) + " -" + + categoryName; + setTitle(title); + + if (taskFiller != null) { + // taskFiller still running + taskFiller.setActivity(this); + startDecryptProgressDialog(); + } + ListAdapter la = getListAdapter(); + if (la != null) { + if (debug) { + Log.d(TAG, "onResume: count=" + la.getCount()); + } + } else { + if (debug) { + Log.d(TAG, "onResume: no list"); + } + /* HACK to make textFilter work!!! * It somehow doesn't work, when there's an empty Adapter after the onResume. */ // List l = new ArrayList(); // l.add(""); // setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, l)); /* /HACK */ - fillData(); - } - } - - @Override - public void onStop() { - super.onStop(); - - if (debug) Log.d(TAG,"onStop()"); - } - @Override - public void onCreateContextMenu(ContextMenu menu, View view, - ContextMenuInfo menuInfo) { - - AdapterView.AdapterContextMenuInfo info; - info = (AdapterView.AdapterContextMenuInfo) menuInfo; - - menu.setHeaderTitle(rows.get(info.position).plainDescription); - menu.add(0, VIEW_PASSWORD_INDEX, 0, R.string.password_view) - .setIcon(android.R.drawable.ic_menu_view) - .setAlphabeticShortcut('v'); - menu.add(0, EDIT_PASSWORD_INDEX, 0, R.string.password_edit) - .setIcon(android.R.drawable.ic_menu_edit) - .setAlphabeticShortcut('e'); - menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete) - .setIcon(android.R.drawable.ic_menu_delete) - .setAlphabeticShortcut('d'); - menu.add(0, MOVE_PASSWORD_INDEX, 0, R.string.move) - .setIcon(android.R.drawable.ic_menu_more) - .setAlphabeticShortcut('m'); - } - @Override - public boolean onContextItemSelected(MenuItem item) { - onOptionsItemSelected(item); - return true; - } - - private void startDecryptProgressDialog() { - if (decryptProgress == null) { - decryptProgress = new ProgressDialog(this); - decryptProgress.setMessage(getString(R.string.decrypt_progress)); - decryptProgress.setIndeterminate(false); - decryptProgress.setCancelable(true); - } - decryptProgress.show(); - } - - /** - * Populates the password ListView - */ - private void fillData() { - if (taskFiller!=null) { - // there's already a running filler - return; - } - startDecryptProgressDialog(); - taskFiller = new fillerTask(); - taskFiller.setActivity(this); - taskFiller.execute(new String[] { null }); - } - - private class fillerTask extends AsyncTask { - PassList currentActivity=null; - public void setActivity(PassList act) { - currentActivity=act; - } - @Override - protected String doInBackground(String... unused) { - - if (debug) Log.d(TAG,"CategoryId="+CategoryId); - rows=Passwords.getPassEntries(CategoryId, true, true); - passDescriptions.clear(); - if (rows!=null) { - Iterator passIter=rows.iterator(); - while (passIter.hasNext()) { - PassEntry passEntry=passIter.next(); - passDescriptions.add(passEntry.plainDescription); - } - } - if (debug) Log.d(TAG,"doInBackground complete"); - return null; - } - - @Override - protected void onPostExecute(String result) { - if (currentActivity != null) { - // because the activity can change on orientation change, we - // need to be sure to set values - // on the currentActivity. Otherwise the user can change - // orientation while we're working on the background - // task and we won't be setting values against the activity - // that's being displayed - passDescriptions4Adapter.clear(); - passDescriptions4Adapter.addAll(passDescriptions); - ArrayAdapter entries = new ArrayAdapter( - PassList.this, android.R.layout.simple_list_item_1, - passDescriptions4Adapter); - currentActivity.setListAdapter(entries); - currentActivity.rows = rows; - if (debug) - Log.d(TAG, "entries.getCount=" + entries.getCount()); - if (debug) - Log.d(TAG, "lastPosition=" + currentActivity.lastPosition); - if (currentActivity.lastPosition > 2) { - currentActivity - .setSelection(currentActivity.lastPosition - 1); - currentActivity.lastPosition = 0; - } - if (currentActivity.decryptProgress != null) { - currentActivity.decryptProgress.dismiss(); - } - } - - taskFiller = null; - } - } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - - if (menu == null) { - return super.onMenuOpened(featureId, menu); - } - MenuItem miDel = menu.findItem(DEL_PASSWORD_INDEX); - MenuItem miMove = menu.findItem(MOVE_PASSWORD_INDEX); - if (getSelectedItemPosition() > -1) { - miDel.setEnabled(true); - miMove.setEnabled(true); - } else { - miDel.setEnabled(false); - miMove.setEnabled(false); - } - return super.onMenuOpened(featureId, menu); - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem item = menu.add(0, ADD_PASSWORD_INDEX, 0, R.string.password_add); - item.setShortcut('2', 'a'); - if (CheckWrappers.mActionBarAvailable) { - item.setIcon(R.drawable.ic_menu_add_password); - WrapActionBar.showIfRoom(item); - } else { - item.setIcon(android.R.drawable.ic_menu_add); - } - - menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete) - .setIcon(android.R.drawable.ic_menu_delete) - .setShortcut('3', 'd'); - - menu.add(0, MOVE_PASSWORD_INDEX, 0, R.string.move) - .setIcon(android.R.drawable.ic_menu_more) - .setShortcut('4', 'm'); - - return super.onCreateOptionsMenu(menu); - } - - private void addPassword() { - Intent i = new Intent(this, PassEdit.class); - i.putExtra(PassList.KEY_ID, (long)-1); - i.putExtra(PassList.KEY_CATEGORY_ID, CategoryId); - startActivityForResult(i,REQUEST_ADD_PASSWORD); - } - /** - * Prompt the user with a dialog asking them if they really want - * to delete the password. - */ - public void deletePassword(final int position){ - Dialog about = new AlertDialog.Builder(this) - .setIcon(R.drawable.passicon) - .setTitle(R.string.dialog_delete_password_title) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - deletePassword2(position); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - // do nothing - } - }) - .setMessage(R.string.dialog_delete_password_msg) - .create(); - about.show(); - } - - /** - * Follow up for the Delete Password dialog. If we have a RowId then - * delete the password, otherwise just finish this Activity. - */ - public void deletePassword2(int position){ - try { - lastPosition=position; - delPassword(rows.get(position).id); - } catch (IndexOutOfBoundsException e) { - // This should only happen when there are no - // entries to delete. - Log.w(TAG,e.toString()); - } - } - - private void delPassword(long Id) { - Passwords.deletePassEntry(Id); - fillData(); - } - - /** - * Prompt the user with Categories to move the specified - * password to and then update the password entry accordingly. - * - * @param passwordId - */ - private void movePassword(final long passwordId) { - final HashMap categoryToId=Passwords.getCategoryNameToId(); - String categoryName=Passwords.getCategoryEntry(CategoryId).plainName; - categoryToId.remove(categoryName); - Set categories=categoryToId.keySet(); - final String[] items=(String[])categories.toArray(new String[categories.size()]); - Arrays.sort(items, String.CASE_INSENSITIVE_ORDER); - - new AlertDialog.Builder(PassList.this) - .setTitle(R.string.move_select) - .setItems(items, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - - long newCategoryId=categoryToId.get(items[which]); - Passwords.updatePassCategory(passwordId, newCategoryId); - String result=getString(R.string.moved_to, items[which]); - Toast.makeText(PassList.this, result, - Toast.LENGTH_LONG).show(); - fillData(); - } - }) - .show(); - } - - public static long[] getRowsIds(List rows) { - if (debug) Log.d(TAG,"getRowsIds() rows="+rows); - if (rows!=null) { - long[] ids=new long[rows.size()]; - Iterator passIter=rows.iterator(); - int i=0; - while (passIter.hasNext()) { - ids[i]=passIter.next().id; - i++; - } - return ids; - } else { - return null; - } - } - - private void viewPassword(int position) { - Intent vi = new Intent(this, PassView.class); - vi.putExtra(KEY_ID, rows.get(position).id); - vi.putExtra(KEY_CATEGORY_ID, CategoryId); - vi.putExtra(KEY_ROWIDS, getRowsIds(rows)); - vi.putExtra(KEY_LIST_POSITION, position); - startActivityForResult(vi,REQUEST_VIEW_PASSWORD); - } - - public boolean onOptionsItemSelected(MenuItem item) { - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); - int position=-1; - if (info==null) { - position=getSelectedItemPosition(); - } else { - // used when this is called from a ContextMenu - position=info.position; - } - - switch(item.getItemId()) { - case android.R.id.home: - Intent intent = new Intent(this, CategoryList.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - break; - case ADD_PASSWORD_INDEX: - addPassword(); - break; - case VIEW_PASSWORD_INDEX: - viewPassword(position); - lastPosition=position; - break; - case EDIT_PASSWORD_INDEX: - Intent i = new Intent(this, PassEdit.class); - i.putExtra(KEY_ID, rows.get(position).id); - i.putExtra(KEY_CATEGORY_ID, CategoryId); - startActivityForResult(i,REQUEST_EDIT_PASSWORD); - lastPosition=position; - break; - case DEL_PASSWORD_INDEX: - deletePassword(position); - break; - case MOVE_PASSWORD_INDEX: - movePassword(rows.get(position).id); - lastPosition=position; - break; - } - return super.onOptionsItemSelected(item); - } - - protected void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - - viewPassword(position); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent i) { - super.onActivityResult(requestCode, resultCode, i); - //Log.d(TAG, "onActivityResult. requestCode: " + requestCode + ", resultCode: " + resultCode); - - if (((requestCode==REQUEST_VIEW_PASSWORD)&&(PassView.entryEdited)) || - ((requestCode==REQUEST_EDIT_PASSWORD)&&(PassEditFragment.entryEdited)) || - ((requestCode==REQUEST_ADD_PASSWORD)&&(PassEditFragment.entryEdited)) || - (resultCode==RESULT_OK)) { - fillData(); - } - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (debug) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + fillData(); + } + } + + @Override + public void onStop() { + super.onStop(); + + if (debug) { + Log.d(TAG, "onStop()"); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, + ContextMenuInfo menuInfo) { + + AdapterView.AdapterContextMenuInfo info; + info = (AdapterView.AdapterContextMenuInfo) menuInfo; + + menu.setHeaderTitle(rows.get(info.position).plainDescription); + menu.add(0, VIEW_PASSWORD_INDEX, 0, R.string.password_view) + .setIcon(android.R.drawable.ic_menu_view) + .setAlphabeticShortcut('v'); + menu.add(0, EDIT_PASSWORD_INDEX, 0, R.string.password_edit) + .setIcon(android.R.drawable.ic_menu_edit) + .setAlphabeticShortcut('e'); + menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete) + .setIcon(android.R.drawable.ic_menu_delete) + .setAlphabeticShortcut('d'); + menu.add(0, MOVE_PASSWORD_INDEX, 0, R.string.move) + .setIcon(android.R.drawable.ic_menu_more) + .setAlphabeticShortcut('m'); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + onOptionsItemSelected(item); + return true; + } + + private void startDecryptProgressDialog() { + if (decryptProgress == null) { + decryptProgress = new ProgressDialog(this); + decryptProgress.setMessage(getString(R.string.decrypt_progress)); + decryptProgress.setIndeterminate(false); + decryptProgress.setCancelable(true); + } + decryptProgress.show(); + } + + /** + * Populates the password ListView + */ + private void fillData() { + if (taskFiller != null) { + // there's already a running filler + return; + } + startDecryptProgressDialog(); + taskFiller = new fillerTask(); + taskFiller.setActivity(this); + taskFiller.execute(new String[]{null}); + } + + private class fillerTask extends AsyncTask { + PassList currentActivity = null; + + public void setActivity(PassList act) { + currentActivity = act; + } + + @Override + protected String doInBackground(String... unused) { + + if (debug) { + Log.d(TAG, "CategoryId=" + CategoryId); + } + rows = Passwords.getPassEntries(CategoryId, true, true); + passDescriptions.clear(); + if (rows != null) { + Iterator passIter = rows.iterator(); + while (passIter.hasNext()) { + PassEntry passEntry = passIter.next(); + passDescriptions.add(passEntry.plainDescription); + } + } + if (debug) { + Log.d(TAG, "doInBackground complete"); + } + return null; + } + + @Override + protected void onPostExecute(String result) { + if (currentActivity != null) { + // because the activity can change on orientation change, we + // need to be sure to set values + // on the currentActivity. Otherwise the user can change + // orientation while we're working on the background + // task and we won't be setting values against the activity + // that's being displayed + passDescriptions4Adapter.clear(); + passDescriptions4Adapter.addAll(passDescriptions); + ArrayAdapter entries = new ArrayAdapter( + PassList.this, android.R.layout.simple_list_item_1, + passDescriptions4Adapter + ); + currentActivity.setListAdapter(entries); + currentActivity.rows = rows; + if (debug) { + Log.d(TAG, "entries.getCount=" + entries.getCount()); + } + if (debug) { + Log.d(TAG, "lastPosition=" + currentActivity.lastPosition); + } + if (currentActivity.lastPosition > 2) { + currentActivity + .setSelection(currentActivity.lastPosition - 1); + currentActivity.lastPosition = 0; + } + if (currentActivity.decryptProgress != null) { + currentActivity.decryptProgress.dismiss(); + } + } + + taskFiller = null; + } + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + + if (menu == null) { + return super.onMenuOpened(featureId, menu); + } + MenuItem miDel = menu.findItem(DEL_PASSWORD_INDEX); + MenuItem miMove = menu.findItem(MOVE_PASSWORD_INDEX); + if (getSelectedItemPosition() > -1) { + miDel.setEnabled(true); + miMove.setEnabled(true); + } else { + miDel.setEnabled(false); + miMove.setEnabled(false); + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + MenuItem item = menu.add(0, ADD_PASSWORD_INDEX, 0, R.string.password_add); + item.setShortcut('2', 'a'); + if (CheckWrappers.mActionBarAvailable) { + item.setIcon(R.drawable.ic_menu_add_password); + WrapActionBar.showIfRoom(item); + } else { + item.setIcon(android.R.drawable.ic_menu_add); + } + + menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete) + .setIcon(android.R.drawable.ic_menu_delete) + .setShortcut('3', 'd'); + + menu.add(0, MOVE_PASSWORD_INDEX, 0, R.string.move) + .setIcon(android.R.drawable.ic_menu_more) + .setShortcut('4', 'm'); + + return super.onCreateOptionsMenu(menu); + } + + private void addPassword() { + Intent i = new Intent(this, PassEdit.class); + i.putExtra(PassList.KEY_ID, (long) -1); + i.putExtra(PassList.KEY_CATEGORY_ID, CategoryId); + startActivityForResult(i, REQUEST_ADD_PASSWORD); + } + + /** + * Prompt the user with a dialog asking them if they really want + * to delete the password. + */ + public void deletePassword(final int position) { + Dialog about = new AlertDialog.Builder(this) + .setIcon(R.drawable.passicon) + .setTitle(R.string.dialog_delete_password_title) + .setPositiveButton( + R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + deletePassword2(position); + } + } + ) + .setNegativeButton( + R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + // do nothing + } + } + ) + .setMessage(R.string.dialog_delete_password_msg) + .create(); + about.show(); + } + + /** + * Follow up for the Delete Password dialog. If we have a RowId then + * delete the password, otherwise just finish this Activity. + */ + public void deletePassword2(int position) { + try { + lastPosition = position; + delPassword(rows.get(position).id); + } catch (IndexOutOfBoundsException e) { + // This should only happen when there are no + // entries to delete. + Log.w(TAG, e.toString()); + } + } + + private void delPassword(long Id) { + Passwords.deletePassEntry(Id); + fillData(); + } + + /** + * Prompt the user with Categories to move the specified + * password to and then update the password entry accordingly. + * + * @param passwordId + */ + private void movePassword(final long passwordId) { + final HashMap categoryToId = Passwords.getCategoryNameToId(); + String categoryName = Passwords.getCategoryEntry(CategoryId).plainName; + categoryToId.remove(categoryName); + Set categories = categoryToId.keySet(); + final String[] items = (String[]) categories.toArray(new String[categories.size()]); + Arrays.sort(items, String.CASE_INSENSITIVE_ORDER); + + new AlertDialog.Builder(PassList.this) + .setTitle(R.string.move_select) + .setItems( + items, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + + long newCategoryId = categoryToId.get(items[which]); + Passwords.updatePassCategory(passwordId, newCategoryId); + String result = getString(R.string.moved_to, items[which]); + Toast.makeText( + PassList.this, result, + Toast.LENGTH_LONG + ).show(); + fillData(); + } + } + ) + .show(); + } + + public static long[] getRowsIds(List rows) { + if (debug) { + Log.d(TAG, "getRowsIds() rows=" + rows); + } + if (rows != null) { + long[] ids = new long[rows.size()]; + Iterator passIter = rows.iterator(); + int i = 0; + while (passIter.hasNext()) { + ids[i] = passIter.next().id; + i++; + } + return ids; + } else { + return null; + } + } + + private void viewPassword(int position) { + Intent vi = new Intent(this, PassView.class); + vi.putExtra(KEY_ID, rows.get(position).id); + vi.putExtra(KEY_CATEGORY_ID, CategoryId); + vi.putExtra(KEY_ROWIDS, getRowsIds(rows)); + vi.putExtra(KEY_LIST_POSITION, position); + startActivityForResult(vi, REQUEST_VIEW_PASSWORD); + } + + public boolean onOptionsItemSelected(MenuItem item) { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); + int position = -1; + if (info == null) { + position = getSelectedItemPosition(); + } else { + // used when this is called from a ContextMenu + position = info.position; + } + + switch (item.getItemId()) { + case android.R.id.home: + Intent intent = new Intent(this, CategoryList.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + break; + case ADD_PASSWORD_INDEX: + addPassword(); + break; + case VIEW_PASSWORD_INDEX: + viewPassword(position); + lastPosition = position; + break; + case EDIT_PASSWORD_INDEX: + Intent i = new Intent(this, PassEdit.class); + i.putExtra(KEY_ID, rows.get(position).id); + i.putExtra(KEY_CATEGORY_ID, CategoryId); + startActivityForResult(i, REQUEST_EDIT_PASSWORD); + lastPosition = position; + break; + case DEL_PASSWORD_INDEX: + deletePassword(position); + break; + case MOVE_PASSWORD_INDEX: + movePassword(rows.get(position).id); + lastPosition = position; + break; + } + return super.onOptionsItemSelected(item); + } + + protected void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + + viewPassword(position); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + //Log.d(TAG, "onActivityResult. requestCode: " + requestCode + ", resultCode: " + resultCode); + + if (((requestCode == REQUEST_VIEW_PASSWORD) && (PassView.entryEdited)) || + ((requestCode == REQUEST_EDIT_PASSWORD) && (PassEditFragment.entryEdited)) || + ((requestCode == REQUEST_ADD_PASSWORD) && (PassEditFragment.entryEdited)) || + (resultCode == RESULT_OK)) { + fillData(); + } + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // startActivity(frontdoor); - }else{ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } - - public boolean onSearchRequested() { - Intent search = new Intent(this, Search.class); - startActivity(search); - return true; - } + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } + + public boolean onSearchRequested() { + Intent search = new Intent(this, Search.class); + startActivity(search); + return true; + } } diff --git a/Safe/src/org/openintents/safe/PassView.java b/Safe/src/org/openintents/safe/PassView.java index 71999549..8763bd98 100644 --- a/Safe/src/org/openintents/safe/PassView.java +++ b/Safe/src/org/openintents/safe/PassView.java @@ -16,13 +16,6 @@ */ package org.openintents.safe; -import java.util.ArrayList; - -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.SimpleGestureFilter.SimpleGestureListener; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.honeycomb.WrapActionBar; - import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -37,8 +30,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; -import org.openintents.safe.wrappers.honeycomb.ClipboardManager; - import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; @@ -55,685 +46,773 @@ import android.widget.Toast; import android.widget.ViewFlipper; +import java.util.ArrayList; + +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.SimpleGestureFilter.SimpleGestureListener; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.honeycomb.ClipboardManager; +import org.openintents.safe.wrappers.honeycomb.WrapActionBar; + /** * PassView Activity - * + * * @author Randy McEoin */ public class PassView extends Activity implements SimpleGestureListener { - private static boolean debug = false; - private static String TAG = "PassView"; - - public static final int EDIT_PASSWORD_INDEX = Menu.FIRST; - public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 1; - - public static final int REQUEST_EDIT_PASS = 1; - - private Long RowId; - private Long CategoryId; - public static boolean entryEdited=false; - private long[] rowids=null; - private int listPosition=-1; - - ViewFlipper flipper=null; - private SimpleGestureFilter detector; - private static int ANIMATION_DURATION=300; - private boolean usernameCopiedToClipboard=false; - - Intent frontdoor; - private Intent restartTimerIntent=null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - if (debug) Log.d(TAG,"onCreate("+icicle+")"); - - // Prevent screen shot shown on recent apps - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, - WindowManager.LayoutParams.FLAG_SECURE); - } - - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent (CryptoIntents.ACTION_RESTART_TIMER); - - String title = getResources().getString(R.string.app_name) + " - " - + getResources().getString(R.string.view_entry); - setTitle(title); - - RowId = icicle != null ? icicle.getLong(PassList.KEY_ID) : null; - if (RowId == null) { - Bundle extras = getIntent().getExtras(); - RowId = extras != null ? extras.getLong(PassList.KEY_ID) : null; - } - CategoryId = icicle != null ? icicle.getLong(PassList.KEY_CATEGORY_ID) : null; - if (CategoryId == null) { - Bundle extras = getIntent().getExtras(); - CategoryId = extras != null ? extras.getLong(PassList.KEY_CATEGORY_ID) : null; - } - rowids = icicle != null ? icicle.getLongArray(PassList.KEY_ROWIDS) : null; - if (rowids == null) { - Bundle extras = getIntent().getExtras(); - rowids = extras != null ? extras.getLongArray(PassList.KEY_ROWIDS) : null; - } - listPosition = icicle != null ? icicle.getInt(PassList.KEY_LIST_POSITION) : -1; - if (listPosition == -1) { - Bundle extras = getIntent().getExtras(); - listPosition = extras != null ? extras.getInt(PassList.KEY_LIST_POSITION) : -1; - } - - if (debug) Log.d(TAG,"RowId="+RowId+" CategoryId="+CategoryId+" rowids="+rowids+ - " listPosition="+listPosition); - if ((RowId==null) || (CategoryId==null) || (rowids==null) || (listPosition==-1) || - (RowId<1) || (CategoryId<1)) { - // invalid Row or Category - finish(); - return; - } - - if (debug) { - for (int i=0; i0) { // is there a previous? - if (debug) Log.d(TAG,"add previous"); - View prevView = createView(listPosition-1,null); - flipper.addView(prevView,0); - flipper.setDisplayedChild(1); - } - - // are we starting at the end and we have more than 2 entries? - if (((listPosition+1)==rowids.length) && (rowids.length > 2)) { - if (debug) Log.d(TAG,"add prev prev"); - View prevView = createView(listPosition-2,null); - flipper.addView(prevView,0); - flipper.setDisplayedChild(2); - } - - if (rowids.length > (listPosition+1)) { // is there a next? - if (debug) Log.d(TAG,"add next"); - View nextView = createView(listPosition+1,null); - if (debug) Log.d(TAG,"flipper ChildCount="+flipper.getChildCount()); - flipper.addView(nextView, flipper.getChildCount()); - } - - // are we starting at the start and we have more than 2 entries? - if ((listPosition==0) && (rowids.length > 2)) { - if (debug) Log.d(TAG,"add next next"); - View nextView = createView(listPosition+2,null); - flipper.addView(nextView,flipper.getChildCount()); - } - - setContentView(flipper); - if (debug) Log.d(TAG,"flipper.getChildCount="+flipper.getChildCount()); - } - - private View createView(int position, View view) { - if (view==null) { - LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = inflater.inflate(R.layout.pass_view,null); - } - if (populateFields(rowids[position],view)==false) { - // failed to retreive record - return null; - } - Button previousButton = (Button) view.findViewById(R.id.prev_pass); - if (position>0) { // is there a previous? - previousButton.setEnabled(true); - previousButton.setOnClickListener(new prevButtonListener()); - } else { - previousButton.setEnabled(false); - } - Button nextButton = (Button) view.findViewById(R.id.next_pass); - if (rowids.length > (position+1)) { // is there a next? - nextButton.setEnabled(true); - nextButton.setOnClickListener(new nextButtonListener()); - } else { - nextButton.setEnabled(false); - } - - Button goButton = (Button) view.findViewById(R.id.go); - goButton.setOnClickListener(new goButtonListener()); - - TextView usernameText = (TextView) view.findViewById(R.id.username); - usernameText.setOnClickListener(new usernameTextListener()); - TextView passwordText = (TextView) view.findViewById(R.id.password); - passwordText.setOnClickListener(new passwordTextListener()); - return view; - } - - class goButtonListener implements View.OnClickListener { - public void onClick(View arg0) { - View current=flipper.getCurrentView(); - TextView passwordText; - TextView websiteText; - websiteText = (TextView) current.findViewById(R.id.website); - passwordText = (TextView) current.findViewById(R.id.password); - - String link = websiteText.getText().toString(); - if (link == null || link.equals("") || link.equals("http://")) { - Toast.makeText(PassView.this, getString(R.string.invalid_url), Toast.LENGTH_SHORT).show(); - return; - } - - if (usernameCopiedToClipboard==false) { - // don't copy the password if username was already copied - clipboard(getString(R.string.password), passwordText.getText().toString()); - } - - Intent i = new Intent(Intent.ACTION_VIEW); - Uri u = Uri.parse(link); - i.setData(u); - try { - startActivity(i); - } catch (ActivityNotFoundException e) { - // Let's try to catch the most common mistake: omitting http: - u = Uri.parse("http://" + link); - i.setData(u); - try { - startActivity(i); - } catch (ActivityNotFoundException e2) { - Toast.makeText(PassView.this, R.string.invalid_website, - Toast.LENGTH_SHORT).show(); - } - } - } - } - - private void showPreviousView(boolean isRightLeft) { - if (listPosition==0) { - // already at the beginning - return; - } - if (isRightLeft) { - flipper.setInAnimation(inFromLeftAnimation()); - flipper.setOutAnimation(outToRightAnimation()); - } else { - flipper.setInAnimation(inFromTopAnimation()); - flipper.setOutAnimation(outToBottomAnimation()); - } - int newChildPosition=flipper.getDisplayedChild()-1; - listPosition--; - RowId=rowids[listPosition]; - if (debug) Log.d(TAG,"previousButton displayedChild="+flipper.getDisplayedChild()+" listPosition="+listPosition); - if ((newChildPosition==0) && (listPosition>0)) { - View last=flipper.getChildAt(flipper.getChildCount()-1); - flipper.removeViewAt(flipper.getChildCount()-1); - View prevView = createView(listPosition-1, last); - flipper.addView(prevView,0); - newChildPosition++; - } - flipper.setDisplayedChild(newChildPosition); - } - class prevButtonListener implements View.OnClickListener { - public void onClick(View arg0) { - if (debug) Log.d(TAG,"previousButton getDisplayedChild="+flipper.getDisplayedChild()); - showPreviousView(true); - } - } - private void showNextView(boolean isRightLeft) { - if ((listPosition+1)==rowids.length) { - // already at the end - return; - } - int displayedChild=flipper.getDisplayedChild(); - if (isRightLeft) { - flipper.setInAnimation(inFromRightAnimation()); - flipper.setOutAnimation(outToLeftAnimation()); - } else { - flipper.setInAnimation(inFromBottomAnimation()); - flipper.setOutAnimation(outToTopAnimation()); - } - flipper.setDisplayedChild(displayedChild+1); - listPosition++; - RowId=rowids[listPosition]; - // did we move beyond something more than the 2nd entry? - if ((rowids.length>3) && (displayedChild>0) && (rowids.length-listPosition>1)){ - View first=flipper.getChildAt(0); - flipper.removeViewAt(0); - View nextView = createView(listPosition+1, first); - flipper.addView(nextView,flipper.getChildCount()); - } - } - class nextButtonListener implements View.OnClickListener { - public void onClick(View arg0) { - if (debug) Log.d(TAG,"nextButton getDisplayedChild="+flipper.getDisplayedChild()); - showNextView(true); - } - } - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (RowId != null) { - outState.putLong(PassList.KEY_ID, RowId); - } else { - outState.putLong(PassList.KEY_ID, -1); - } - outState.putLong(PassList.KEY_CATEGORY_ID, CategoryId); - outState.putLongArray(PassList.KEY_ROWIDS, rowids); - outState.putInt(PassList.KEY_LIST_POSITION, listPosition); - } - - @Override - protected void onPause() { - super.onPause(); - - if (debug) Log.d(TAG,"onPause()"); - - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (debug) Log.d(TAG,"onResume()"); - - if (CategoryList.isSignedIn()==false) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - - Passwords.Initialize(this); - - if (flipper==null) { - initFlipper(); - } - // update in case it was edited - if (entryEdited) { - View current=this.flipper.getCurrentView(); - populateFields(RowId,current); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem item = menu.add(0, EDIT_PASSWORD_INDEX, 0, R.string.password_edit) - .setIcon(android.R.drawable.ic_menu_edit).setShortcut('1', 'e'); - if (CheckWrappers.mActionBarAvailable) { - WrapActionBar.showIfRoom(item); - } - - menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete) - .setIcon(android.R.drawable.ic_menu_delete).setShortcut('2', 'd'); - - return super.onCreateOptionsMenu(menu); - } - - /** - * Prompt the user with a dialog asking them if they really want - * to delete the password. - */ - public void deletePassword(){ - Dialog about = new AlertDialog.Builder(this) - .setIcon(R.drawable.passicon) - .setTitle(R.string.dialog_delete_password_title) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - deletePassword2(); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - // do nothing - } - }) - .setMessage(R.string.dialog_delete_password_msg) - .create(); - about.show(); - } - - /** - * Follow up for the Delete Password dialog. If we have a RowId then - * delete the password, otherwise just finish this Activity. - */ - public void deletePassword2(){ - if ((RowId != null) && (RowId > 0)) { - delPassword(RowId); - } else { - // user specified to delete a new entry - // so simply exit out - finish(); - } - } - /** - * Delete the password entry from the database given the row id within the - * database. - * - * @param Id - */ - private void delPassword(long Id) { - Passwords.deletePassEntry(Id); - setResult(RESULT_OK); - finish(); - } - - /** - * Handler for when a MenuItem is selected from the Activity. - */ - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - break; - case EDIT_PASSWORD_INDEX: - Intent i = new Intent(getApplicationContext(), PassEdit.class); - i.putExtra(PassList.KEY_ID, RowId); - i.putExtra(PassList.KEY_CATEGORY_ID, CategoryId); - startActivityForResult(i, REQUEST_EDIT_PASS); - break; - case DEL_PASSWORD_INDEX: - deletePassword(); - break; - } - return super.onOptionsItemSelected(item); - } - - /** - * - */ - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent i) { - super.onActivityResult(requestCode, resultCode, i); - - if (debug) Log.d(TAG,"onActivityResult()"); - if (requestCode == REQUEST_EDIT_PASS) { - if (resultCode==PassEdit.RESULT_DELETED) { - entryEdited=true; - finish(); - } - if ((resultCode == RESULT_OK) || (PassEditFragment.entryEdited)){ - if (flipper!=null) { - View current=this.flipper.getCurrentView(); - populateFields(RowId,current); - } - entryEdited=true; - } - } - } - - /** - * - */ - private boolean populateFields(long rowIdx, View view) { - if (debug) Log.d(TAG,"populateFields("+rowIdx+","+view+")"); - if (rowIdx > 0) { - if (debug) Log.d(TAG,"rowIdx="+rowIdx); - PassEntry row = Passwords.getPassEntry(rowIdx, true, false); - if (row==null) { - if (debug) Log.d(TAG,"populateFields: row=null"); - return false; - } - ArrayList packageAccess = Passwords.getPackageAccess(rowIdx); - - TextView descriptionText; - TextView passwordText; - TextView usernameText; - TextView websiteText; - TextView noteText; - TextView lastEditedText; - TextView uniqueNameText; - TextView packageAccessText; - - descriptionText = (TextView) view.findViewById(R.id.description); - websiteText = (TextView) view.findViewById(R.id.website); - usernameText = (TextView) view.findViewById(R.id.username); - passwordText = (TextView) view.findViewById(R.id.password); - noteText = (TextView) view.findViewById(R.id.note); - lastEditedText = (TextView) view.findViewById(R.id.last_edited); - uniqueNameText = (TextView) view.findViewById(R.id.uniquename); - packageAccessText = (TextView) view.findViewById(R.id.packageaccess); - - if (debug) { - Log.d(TAG,"populateFields: descriptionText="+descriptionText); - } - descriptionText.setText(row.plainDescription); - websiteText.setText(row.plainWebsite); - usernameText.setText(row.plainUsername); - passwordText.setText(row.plainPassword); - noteText.setText(row.plainNote); - String lastEdited; - if (row.lastEdited!=null) { - lastEdited=row.lastEdited; - } else { - lastEdited=getString(R.string.last_edited_unknown); - } - lastEditedText.setText(getString(R.string.last_edited)+": "+lastEdited); - if (row.plainUniqueName!=null) { - uniqueNameText.setText(getString(R.string.uniquename)+ - ": "+row.plainUniqueName); - } - String packages=""; - if (packageAccess!=null) { - for (String packageName : packageAccess) { - if (debug) Log.d(TAG,"packageName="+packageName); - PackageManager pm=getPackageManager(); - String appLabel=""; - try { - ApplicationInfo ai=pm.getApplicationInfo(packageName,0); - appLabel=pm.getApplicationLabel(ai).toString(); - } catch (NameNotFoundException e) { - appLabel="("+getString(R.string.not_found)+")"; - } - packages+=packageName+" "+appLabel+" "; - } - } - if (packages!="") { - packageAccessText.setText(getString(R.string.package_access)+ - ": "+packages); - } - } - return true; - } - - /** - * - * @author Billy Cui - * refactored by Randy McEoin - */ - class usernameTextListener implements View.OnClickListener { - public void onClick(View arg0) { - TextView usernameText = (TextView) arg0.findViewById(R.id.username); - if (debug) Log.d(TAG, "click " + usernameText.getText()); - clipboard(getString(R.string.username),usernameText.getText().toString()); - usernameCopiedToClipboard=true; - } - } - class passwordTextListener implements View.OnClickListener { - public void onClick(View arg0) { - TextView passwordText = (TextView) arg0.findViewById(R.id.password); - if (debug) Log.d(TAG, "click " + passwordText.getText()); - clipboard(getString(R.string.password),passwordText.getText().toString()); - } - } - /** - * Copy to clipboard and toast to let user know that we have done so. - * - * @author Billy Cui - * @param fieldName Name of the field copied from - * @param value String to copy to clipboard - */ - private void clipboard(String fieldName, String value) { - Toast.makeText(PassView.this, fieldName+" "+getString(R.string.copied_to_clipboard), - Toast.LENGTH_SHORT).show(); - - ClipboardManager cb = ClipboardManager.newInstance(getApplication()); - cb.setText(value); - Safe.last_used_password = value; - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (debug) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + private static boolean debug = false; + private static String TAG = "PassView"; + + public static final int EDIT_PASSWORD_INDEX = Menu.FIRST; + public static final int DEL_PASSWORD_INDEX = Menu.FIRST + 1; + + public static final int REQUEST_EDIT_PASS = 1; + + private Long RowId; + private Long CategoryId; + public static boolean entryEdited = false; + private long[] rowids = null; + private int listPosition = -1; + + ViewFlipper flipper = null; + private SimpleGestureFilter detector; + private static int ANIMATION_DURATION = 300; + private boolean usernameCopiedToClipboard = false; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; + + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + if (debug) { + Log.d(TAG, "onCreate(" + icicle + ")"); + } + + // Prevent screen shot shown on recent apps + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + getWindow().setFlags( + WindowManager.LayoutParams.FLAG_SECURE, + WindowManager.LayoutParams.FLAG_SECURE + ); + } + + frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.view_entry); + setTitle(title); + + RowId = icicle != null ? icicle.getLong(PassList.KEY_ID) : null; + if (RowId == null) { + Bundle extras = getIntent().getExtras(); + RowId = extras != null ? extras.getLong(PassList.KEY_ID) : null; + } + CategoryId = icicle != null ? icicle.getLong(PassList.KEY_CATEGORY_ID) : null; + if (CategoryId == null) { + Bundle extras = getIntent().getExtras(); + CategoryId = extras != null ? extras.getLong(PassList.KEY_CATEGORY_ID) : null; + } + rowids = icicle != null ? icicle.getLongArray(PassList.KEY_ROWIDS) : null; + if (rowids == null) { + Bundle extras = getIntent().getExtras(); + rowids = extras != null ? extras.getLongArray(PassList.KEY_ROWIDS) : null; + } + listPosition = icicle != null ? icicle.getInt(PassList.KEY_LIST_POSITION) : -1; + if (listPosition == -1) { + Bundle extras = getIntent().getExtras(); + listPosition = extras != null ? extras.getInt(PassList.KEY_LIST_POSITION) : -1; + } + + if (debug) { + Log.d( + TAG, "RowId=" + RowId + " CategoryId=" + CategoryId + " rowids=" + rowids + + " listPosition=" + listPosition + ); + } + if ((RowId == null) || (CategoryId == null) || (rowids == null) || (listPosition == -1) || + (RowId < 1) || (CategoryId < 1)) { + // invalid Row or Category + finish(); + return; + } + + if (debug) { + for (int i = 0; i < rowids.length; i++) { + Log.d(TAG, "rowids[" + i + "]=" + rowids[i]); + } + } + if (debug) { + Log.d(TAG, "rowids.length=" + rowids.length); + } + + detector = new SimpleGestureFilter(this, this); + DisplayMetrics metrics = getResources().getDisplayMetrics(); + int width = metrics.widthPixels; + detector.setViewWidth(width); + + entryEdited = false; + + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar bar = new WrapActionBar(this); + bar.setDisplayHomeAsUpEnabled(true); + } + + } + + private void initFlipper() { + + if (debug) { + Log.d(TAG, "creating flipper"); + } + flipper = new ViewFlipper(this); + View currentView = createView(listPosition, null); + if (currentView == null) { + // failed to create the view + finish(); + return; + } + flipper.addView(currentView); + + if (listPosition > 0) { // is there a previous? + if (debug) { + Log.d(TAG, "add previous"); + } + View prevView = createView(listPosition - 1, null); + flipper.addView(prevView, 0); + flipper.setDisplayedChild(1); + } + + // are we starting at the end and we have more than 2 entries? + if (((listPosition + 1) == rowids.length) && (rowids.length > 2)) { + if (debug) { + Log.d(TAG, "add prev prev"); + } + View prevView = createView(listPosition - 2, null); + flipper.addView(prevView, 0); + flipper.setDisplayedChild(2); + } + + if (rowids.length > (listPosition + 1)) { // is there a next? + if (debug) { + Log.d(TAG, "add next"); + } + View nextView = createView(listPosition + 1, null); + if (debug) { + Log.d(TAG, "flipper ChildCount=" + flipper.getChildCount()); + } + flipper.addView(nextView, flipper.getChildCount()); + } + + // are we starting at the start and we have more than 2 entries? + if ((listPosition == 0) && (rowids.length > 2)) { + if (debug) { + Log.d(TAG, "add next next"); + } + View nextView = createView(listPosition + 2, null); + flipper.addView(nextView, flipper.getChildCount()); + } + + setContentView(flipper); + if (debug) { + Log.d(TAG, "flipper.getChildCount=" + flipper.getChildCount()); + } + } + + private View createView(int position, View view) { + if (view == null) { + LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = inflater.inflate(R.layout.pass_view, null); + } + if (populateFields(rowids[position], view) == false) { + // failed to retreive record + return null; + } + Button previousButton = (Button) view.findViewById(R.id.prev_pass); + if (position > 0) { // is there a previous? + previousButton.setEnabled(true); + previousButton.setOnClickListener(new prevButtonListener()); + } else { + previousButton.setEnabled(false); + } + Button nextButton = (Button) view.findViewById(R.id.next_pass); + if (rowids.length > (position + 1)) { // is there a next? + nextButton.setEnabled(true); + nextButton.setOnClickListener(new nextButtonListener()); + } else { + nextButton.setEnabled(false); + } + + Button goButton = (Button) view.findViewById(R.id.go); + goButton.setOnClickListener(new goButtonListener()); + + TextView usernameText = (TextView) view.findViewById(R.id.username); + usernameText.setOnClickListener(new usernameTextListener()); + TextView passwordText = (TextView) view.findViewById(R.id.password); + passwordText.setOnClickListener(new passwordTextListener()); + return view; + } + + class goButtonListener implements View.OnClickListener { + public void onClick(View arg0) { + View current = flipper.getCurrentView(); + TextView passwordText; + TextView websiteText; + websiteText = (TextView) current.findViewById(R.id.website); + passwordText = (TextView) current.findViewById(R.id.password); + + String link = websiteText.getText().toString(); + if (link == null || link.equals("") || link.equals("http://")) { + Toast.makeText(PassView.this, getString(R.string.invalid_url), Toast.LENGTH_SHORT).show(); + return; + } + + if (usernameCopiedToClipboard == false) { + // don't copy the password if username was already copied + clipboard(getString(R.string.password), passwordText.getText().toString()); + } + + Intent i = new Intent(Intent.ACTION_VIEW); + Uri u = Uri.parse(link); + i.setData(u); + try { + startActivity(i); + } catch (ActivityNotFoundException e) { + // Let's try to catch the most common mistake: omitting http: + u = Uri.parse("http://" + link); + i.setData(u); + try { + startActivity(i); + } catch (ActivityNotFoundException e2) { + Toast.makeText( + PassView.this, R.string.invalid_website, + Toast.LENGTH_SHORT + ).show(); + } + } + } + } + + private void showPreviousView(boolean isRightLeft) { + if (listPosition == 0) { + // already at the beginning + return; + } + if (isRightLeft) { + flipper.setInAnimation(inFromLeftAnimation()); + flipper.setOutAnimation(outToRightAnimation()); + } else { + flipper.setInAnimation(inFromTopAnimation()); + flipper.setOutAnimation(outToBottomAnimation()); + } + int newChildPosition = flipper.getDisplayedChild() - 1; + listPosition--; + RowId = rowids[listPosition]; + if (debug) { + Log.d(TAG, "previousButton displayedChild=" + flipper.getDisplayedChild() + " listPosition=" + listPosition); + } + if ((newChildPosition == 0) && (listPosition > 0)) { + View last = flipper.getChildAt(flipper.getChildCount() - 1); + flipper.removeViewAt(flipper.getChildCount() - 1); + View prevView = createView(listPosition - 1, last); + flipper.addView(prevView, 0); + newChildPosition++; + } + flipper.setDisplayedChild(newChildPosition); + } + + class prevButtonListener implements View.OnClickListener { + public void onClick(View arg0) { + if (debug) { + Log.d(TAG, "previousButton getDisplayedChild=" + flipper.getDisplayedChild()); + } + showPreviousView(true); + } + } + + private void showNextView(boolean isRightLeft) { + if ((listPosition + 1) == rowids.length) { + // already at the end + return; + } + int displayedChild = flipper.getDisplayedChild(); + if (isRightLeft) { + flipper.setInAnimation(inFromRightAnimation()); + flipper.setOutAnimation(outToLeftAnimation()); + } else { + flipper.setInAnimation(inFromBottomAnimation()); + flipper.setOutAnimation(outToTopAnimation()); + } + flipper.setDisplayedChild(displayedChild + 1); + listPosition++; + RowId = rowids[listPosition]; + // did we move beyond something more than the 2nd entry? + if ((rowids.length > 3) && (displayedChild > 0) && (rowids.length - listPosition > 1)) { + View first = flipper.getChildAt(0); + flipper.removeViewAt(0); + View nextView = createView(listPosition + 1, first); + flipper.addView(nextView, flipper.getChildCount()); + } + } + + class nextButtonListener implements View.OnClickListener { + public void onClick(View arg0) { + if (debug) { + Log.d(TAG, "nextButton getDisplayedChild=" + flipper.getDisplayedChild()); + } + showNextView(true); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (RowId != null) { + outState.putLong(PassList.KEY_ID, RowId); + } else { + outState.putLong(PassList.KEY_ID, -1); + } + outState.putLong(PassList.KEY_CATEGORY_ID, CategoryId); + outState.putLongArray(PassList.KEY_ROWIDS, rowids); + outState.putInt(PassList.KEY_LIST_POSITION, listPosition); + } + + @Override + protected void onPause() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onPause()"); + } + + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + + if (CategoryList.isSignedIn() == false) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + + Passwords.Initialize(this); + + if (flipper == null) { + initFlipper(); + } + // update in case it was edited + if (entryEdited) { + View current = this.flipper.getCurrentView(); + populateFields(RowId, current); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + MenuItem item = menu.add(0, EDIT_PASSWORD_INDEX, 0, R.string.password_edit) + .setIcon(android.R.drawable.ic_menu_edit).setShortcut('1', 'e'); + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar.showIfRoom(item); + } + + menu.add(0, DEL_PASSWORD_INDEX, 0, R.string.password_delete) + .setIcon(android.R.drawable.ic_menu_delete).setShortcut('2', 'd'); + + return super.onCreateOptionsMenu(menu); + } + + /** + * Prompt the user with a dialog asking them if they really want + * to delete the password. + */ + public void deletePassword() { + Dialog about = new AlertDialog.Builder(this) + .setIcon(R.drawable.passicon) + .setTitle(R.string.dialog_delete_password_title) + .setPositiveButton( + R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + deletePassword2(); + } + } + ) + .setNegativeButton( + R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + // do nothing + } + } + ) + .setMessage(R.string.dialog_delete_password_msg) + .create(); + about.show(); + } + + /** + * Follow up for the Delete Password dialog. If we have a RowId then + * delete the password, otherwise just finish this Activity. + */ + public void deletePassword2() { + if ((RowId != null) && (RowId > 0)) { + delPassword(RowId); + } else { + // user specified to delete a new entry + // so simply exit out + finish(); + } + } + + /** + * Delete the password entry from the database given the row id within the + * database. + * + * @param Id + */ + private void delPassword(long Id) { + Passwords.deletePassEntry(Id); + setResult(RESULT_OK); + finish(); + } + + /** + * Handler for when a MenuItem is selected from the Activity. + */ + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + case EDIT_PASSWORD_INDEX: + Intent i = new Intent(getApplicationContext(), PassEdit.class); + i.putExtra(PassList.KEY_ID, RowId); + i.putExtra(PassList.KEY_CATEGORY_ID, CategoryId); + startActivityForResult(i, REQUEST_EDIT_PASS); + break; + case DEL_PASSWORD_INDEX: + deletePassword(); + break; + } + return super.onOptionsItemSelected(item); + } + + /** + * + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + + if (debug) { + Log.d(TAG, "onActivityResult()"); + } + if (requestCode == REQUEST_EDIT_PASS) { + if (resultCode == PassEdit.RESULT_DELETED) { + entryEdited = true; + finish(); + } + if ((resultCode == RESULT_OK) || (PassEditFragment.entryEdited)) { + if (flipper != null) { + View current = this.flipper.getCurrentView(); + populateFields(RowId, current); + } + entryEdited = true; + } + } + } + + /** + * + */ + private boolean populateFields(long rowIdx, View view) { + if (debug) { + Log.d(TAG, "populateFields(" + rowIdx + "," + view + ")"); + } + if (rowIdx > 0) { + if (debug) { + Log.d(TAG, "rowIdx=" + rowIdx); + } + PassEntry row = Passwords.getPassEntry(rowIdx, true, false); + if (row == null) { + if (debug) { + Log.d(TAG, "populateFields: row=null"); + } + return false; + } + ArrayList packageAccess = Passwords.getPackageAccess(rowIdx); + + TextView descriptionText; + TextView passwordText; + TextView usernameText; + TextView websiteText; + TextView noteText; + TextView lastEditedText; + TextView uniqueNameText; + TextView packageAccessText; + + descriptionText = (TextView) view.findViewById(R.id.description); + websiteText = (TextView) view.findViewById(R.id.website); + usernameText = (TextView) view.findViewById(R.id.username); + passwordText = (TextView) view.findViewById(R.id.password); + noteText = (TextView) view.findViewById(R.id.note); + lastEditedText = (TextView) view.findViewById(R.id.last_edited); + uniqueNameText = (TextView) view.findViewById(R.id.uniquename); + packageAccessText = (TextView) view.findViewById(R.id.packageaccess); + + if (debug) { + Log.d(TAG, "populateFields: descriptionText=" + descriptionText); + } + descriptionText.setText(row.plainDescription); + websiteText.setText(row.plainWebsite); + usernameText.setText(row.plainUsername); + passwordText.setText(row.plainPassword); + noteText.setText(row.plainNote); + String lastEdited; + if (row.lastEdited != null) { + lastEdited = row.lastEdited; + } else { + lastEdited = getString(R.string.last_edited_unknown); + } + lastEditedText.setText(getString(R.string.last_edited) + ": " + lastEdited); + if (row.plainUniqueName != null) { + uniqueNameText.setText( + getString(R.string.uniquename) + + ": " + row.plainUniqueName + ); + } + String packages = ""; + if (packageAccess != null) { + for (String packageName : packageAccess) { + if (debug) { + Log.d(TAG, "packageName=" + packageName); + } + PackageManager pm = getPackageManager(); + String appLabel = ""; + try { + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + appLabel = pm.getApplicationLabel(ai).toString(); + } catch (NameNotFoundException e) { + appLabel = "(" + getString(R.string.not_found) + ")"; + } + packages += packageName + " " + appLabel + " "; + } + } + if (packages != "") { + packageAccessText.setText( + getString(R.string.package_access) + + ": " + packages + ); + } + } + return true; + } + + /** + * @author Billy Cui + * refactored by Randy McEoin + */ + class usernameTextListener implements View.OnClickListener { + public void onClick(View arg0) { + TextView usernameText = (TextView) arg0.findViewById(R.id.username); + if (debug) { + Log.d(TAG, "click " + usernameText.getText()); + } + clipboard(getString(R.string.username), usernameText.getText().toString()); + usernameCopiedToClipboard = true; + } + } + + class passwordTextListener implements View.OnClickListener { + public void onClick(View arg0) { + TextView passwordText = (TextView) arg0.findViewById(R.id.password); + if (debug) { + Log.d(TAG, "click " + passwordText.getText()); + } + clipboard(getString(R.string.password), passwordText.getText().toString()); + } + } + + /** + * Copy to clipboard and toast to let user know that we have done so. + * + * @param fieldName Name of the field copied from + * @param value String to copy to clipboard + * @author Billy Cui + */ + private void clipboard(String fieldName, String value) { + Toast.makeText( + PassView.this, fieldName + " " + getString(R.string.copied_to_clipboard), + Toast.LENGTH_SHORT + ).show(); + + ClipboardManager cb = ClipboardManager.newInstance(getApplication()); + cb.setText(value); + Safe.last_used_password = value; + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // startActivity(frontdoor); - }else{ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } - private Animation inFromRightAnimation() { - Animation inFromRight = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, +1.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f); - inFromRight.setDuration(ANIMATION_DURATION); - inFromRight.setInterpolator(new AccelerateInterpolator()); - return inFromRight; - } - - private Animation outToLeftAnimation() { - Animation outtoLeft = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, -1.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f); - outtoLeft.setDuration(ANIMATION_DURATION); - outtoLeft.setInterpolator(new AccelerateInterpolator()); - return outtoLeft; - } - - private Animation inFromLeftAnimation() { - Animation inFromLeft = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, -1.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f); - inFromLeft.setDuration(ANIMATION_DURATION); - inFromLeft.setInterpolator(new AccelerateInterpolator()); - return inFromLeft; - } - - private Animation outToRightAnimation() { - Animation outtoRight = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, +1.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f); - outtoRight.setDuration(ANIMATION_DURATION); - outtoRight.setInterpolator(new AccelerateInterpolator()); - return outtoRight; - } - - private Animation inFromBottomAnimation() { - Animation inFromBottom = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, +1.0f, - Animation.RELATIVE_TO_PARENT, 0.0f); - inFromBottom.setDuration(ANIMATION_DURATION); - inFromBottom.setInterpolator(new AccelerateInterpolator()); - return inFromBottom; - } - - private Animation outToTopAnimation() { - Animation outtoTop = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, -1.0f); - outtoTop.setDuration(ANIMATION_DURATION); - outtoTop.setInterpolator(new AccelerateInterpolator()); - return outtoTop; - } - - private Animation inFromTopAnimation() { - Animation inFromTop = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, -1.0f, - Animation.RELATIVE_TO_PARENT, 0.0f); - inFromTop.setDuration(ANIMATION_DURATION); - inFromTop.setInterpolator(new AccelerateInterpolator()); - return inFromTop; - } - - private Animation outToBottomAnimation() { - Animation outToBottom = new TranslateAnimation( - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, 0.0f, - Animation.RELATIVE_TO_PARENT, +1.0f); - outToBottom.setDuration(ANIMATION_DURATION); - outToBottom.setInterpolator(new AccelerateInterpolator()); - return outToBottom; - } - @Override - public boolean dispatchTouchEvent(MotionEvent me){ - this.detector.onTouchEvent(me); - return super.dispatchTouchEvent(me); - } - - public void onSwipe(int direction) { - switch (direction) { - case SimpleGestureFilter.SWIPE_RIGHT: - showPreviousView(true); - break; - case SimpleGestureFilter.SWIPE_LEFT: - showNextView(true); - break; - } - } - - public void onDoubleTap() { - } - - public boolean onSearchRequested() { - Intent search = new Intent(this, Search.class); - startActivity(search); - return true; - } + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } + + private Animation inFromRightAnimation() { + Animation inFromRight = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, +1.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f + ); + inFromRight.setDuration(ANIMATION_DURATION); + inFromRight.setInterpolator(new AccelerateInterpolator()); + return inFromRight; + } + + private Animation outToLeftAnimation() { + Animation outtoLeft = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, -1.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f + ); + outtoLeft.setDuration(ANIMATION_DURATION); + outtoLeft.setInterpolator(new AccelerateInterpolator()); + return outtoLeft; + } + + private Animation inFromLeftAnimation() { + Animation inFromLeft = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, -1.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f + ); + inFromLeft.setDuration(ANIMATION_DURATION); + inFromLeft.setInterpolator(new AccelerateInterpolator()); + return inFromLeft; + } + + private Animation outToRightAnimation() { + Animation outtoRight = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, +1.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f + ); + outtoRight.setDuration(ANIMATION_DURATION); + outtoRight.setInterpolator(new AccelerateInterpolator()); + return outtoRight; + } + + private Animation inFromBottomAnimation() { + Animation inFromBottom = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, +1.0f, + Animation.RELATIVE_TO_PARENT, 0.0f + ); + inFromBottom.setDuration(ANIMATION_DURATION); + inFromBottom.setInterpolator(new AccelerateInterpolator()); + return inFromBottom; + } + + private Animation outToTopAnimation() { + Animation outtoTop = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, -1.0f + ); + outtoTop.setDuration(ANIMATION_DURATION); + outtoTop.setInterpolator(new AccelerateInterpolator()); + return outtoTop; + } + + private Animation inFromTopAnimation() { + Animation inFromTop = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, -1.0f, + Animation.RELATIVE_TO_PARENT, 0.0f + ); + inFromTop.setDuration(ANIMATION_DURATION); + inFromTop.setInterpolator(new AccelerateInterpolator()); + return inFromTop; + } + + private Animation outToBottomAnimation() { + Animation outToBottom = new TranslateAnimation( + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, 0.0f, + Animation.RELATIVE_TO_PARENT, +1.0f + ); + outToBottom.setDuration(ANIMATION_DURATION); + outToBottom.setInterpolator(new AccelerateInterpolator()); + return outToBottom; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent me) { + this.detector.onTouchEvent(me); + return super.dispatchTouchEvent(me); + } + + public void onSwipe(int direction) { + switch (direction) { + case SimpleGestureFilter.SWIPE_RIGHT: + showPreviousView(true); + break; + case SimpleGestureFilter.SWIPE_LEFT: + showNextView(true); + break; + } + } + + public void onDoubleTap() { + } + + public boolean onSearchRequested() { + Intent search = new Intent(this, Search.class); + startActivity(search); + return true; + } } diff --git a/Safe/src/org/openintents/safe/Passwords.java b/Safe/src/org/openintents/safe/Passwords.java index 66cbf826..08aaefb9 100644 --- a/Safe/src/org/openintents/safe/Passwords.java +++ b/Safe/src/org/openintents/safe/Passwords.java @@ -16,6 +16,10 @@ package org.openintents.safe; +import android.content.Context; +import android.util.Log; +import android.widget.Toast; + import java.text.DateFormat; import java.util.ArrayList; import java.util.Collection; @@ -29,523 +33,555 @@ import org.openintents.safe.password.Master; -import android.content.Context; -import android.util.Log; -import android.widget.Toast; - /** * Abstraction layer for storing encrypted and decrypted versions * of all PassEntry and CategoryEntry data. * Handles fetching and storing with DBHelper * and encrypt/decrypt of data. - * - * @author Randy McEoin * + * @author Randy McEoin */ public class Passwords { - private static final boolean debug = false; - private static final String TAG = "Passwords"; - - private static HashMap passEntries=null; - - private static HashMap categoryEntries=null; - - private static HashMap> packageAccessEntries=null; - - private static CryptoHelper ch=null; - private static boolean cryptoInitialized=false; - - private static DBHelper dbHelper=null; - - public static boolean Initialize(Context ctx) { - if (debug) Log.d(TAG,"Initialize()"); - - if (ch==null) { - ch = new CryptoHelper(); - } - if ((cryptoInitialized==false) && - (Master.getSalt()!=null) && - (Master.getMasterKey()!=null)) - { - try { - Passwords.InitCrypto(CryptoHelper.EncryptionMedium, - Master.getSalt(), Master.getMasterKey()); - cryptoInitialized=true; - } catch (Exception e) { - e.printStackTrace(); - Toast.makeText(ctx, "CategoryList: " + ctx.getString(R.string.crypto_error), - Toast.LENGTH_SHORT).show(); - } - } - - if (dbHelper==null) { - dbHelper = new DBHelper(ctx); - if (dbHelper.isDatabaseOpen()==false) { - return false; - } - } - if (passEntries==null) { - passEntries = new HashMap(); - InitPassEntries(); - } - if (categoryEntries==null) { - categoryEntries = new HashMap(); - InitCategoryEntries(); - } - if (packageAccessEntries==null) { - packageAccessEntries = new HashMap>(); - InitPackageAccess(); - } - return true; - } - - /** - * Force a fresh load from the database. - */ - public static void Reset() { - categoryEntries.clear(); - InitCategoryEntries(); - passEntries.clear(); - InitPassEntries(); - packageAccessEntries.clear(); - InitPackageAccess(); - } - - public static void InitCrypto(int strength, String salt, String masterKey) - throws Exception { - if (debug) Log.d(TAG,"InitCrypto("+strength+","+salt+","+masterKey); - try { - ch.init(strength,salt); - ch.setPassword(masterKey); - } catch (CryptoHelperException e1) { - e1.printStackTrace(); - throw new Exception("Error with Passwords.InitCrypto: "+ - e1.getLocalizedMessage()); - } - } - - public static boolean isCryptoInitialized() { - return cryptoInitialized; - } - public static void deleteAll() { - dbHelper.deleteDatabase(); - Reset(); - } - - public static boolean getPrePopulate() { - return dbHelper.getPrePopulate(); - } - - public static void clearPrePopulate() { - dbHelper.clearPrePopulate(); - } - - public static String fetchSalt() { - return dbHelper.fetchSalt(); - } - - public static String fetchMasterKeyEncrypted() { - return dbHelper.fetchMasterKey(); - } - /////////////////////////////////////////////////// - ///////////// Category Functions ////////////////// - /////////////////////////////////////////////////// - - private static void InitCategoryEntries() { - List catRows; - catRows = dbHelper.fetchAllCategoryRows(); - for (CategoryEntry catRow : catRows) { - catRow.nameNeedsDecrypt=true; - catRow.plainNameNeedsEncrypt=false; - categoryEntries.put(catRow.id, catRow); - } - } - - public static List getCategoryEntries() { - Collection categories=categoryEntries.values(); - Iterator catIter=categories.iterator(); - while (catIter.hasNext()) { - CategoryEntry catEntry=catIter.next(); - // run through and ensure all entries are decrypted - getCategoryEntry(catEntry.id); - } - List catList=new ArrayList(categories); - Collections.sort(catList, new Comparator() { - public int compare(CategoryEntry o1, CategoryEntry o2) { - return o1.plainName.compareToIgnoreCase(o2.plainName); - }}); - return catList; - } - - public static List getCategoryNames() { - List items = new ArrayList(); - - List catList=getCategoryEntries(); - for (CategoryEntry row : catList) { - items.add(row.plainName); - } - return items; - } - - public static HashMap getCategoryIdToName() { - HashMap categoryMap = new HashMap(); - Collection categories=categoryEntries.values(); - Iterator catIter=categories.iterator(); - while (catIter.hasNext()) { - CategoryEntry catEntry=catIter.next(); - // run through and ensure all entries are decrypted - getCategoryEntry(catEntry.id); - categoryMap.put(catEntry.id, catEntry.plainName); - } - return categoryMap; - } - - public static HashMap getCategoryNameToId() { - HashMap categoryMap = new HashMap(); - Collection categories=categoryEntries.values(); - Iterator catIter=categories.iterator(); - while (catIter.hasNext()) { - CategoryEntry catEntry=catIter.next(); - // run through and ensure all entries are decrypted - getCategoryEntry(catEntry.id); - categoryMap.put(catEntry.plainName, catEntry.id); - if (debug) Log.d(TAG,"map "+catEntry.plainName+" to "+catEntry.id); - } - return categoryMap; - } - - public static CategoryEntry getCategoryEntryByName(String category) { - Collection categories=categoryEntries.values(); - Iterator catIter=categories.iterator(); - while (catIter.hasNext()) { - CategoryEntry catEntry=catIter.next(); - if (catEntry.name.compareTo(category)==0) { - return catEntry; - } - } - return null; - } - - public static CategoryEntry getCategoryEntry(Long id) { - CategoryEntry catEntry=categoryEntries.get(id); - if (catEntry==null) { - return null; - } - if (catEntry.nameNeedsDecrypt) { - if (debug) Log.d(TAG,"decrypt cat"); - try { - catEntry.plainName = ch.decrypt(catEntry.name); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - } - catEntry.nameNeedsDecrypt=false; - categoryEntries.put(id, catEntry); - } - catEntry.count=dbHelper.getCategoryCount(id); - return catEntry; - } - - public static long putCategoryEntry(CategoryEntry catEntry) { - if (catEntry.plainNameNeedsEncrypt) { - if (debug) Log.d(TAG,"encrypt cat"); - try { - catEntry.name = ch.encrypt(catEntry.plainName); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - } - catEntry.plainNameNeedsEncrypt=false; - } - if (catEntry.id==-1) { - catEntry.id=dbHelper.addCategory(catEntry); - } else { - dbHelper.updateCategory(catEntry.id, catEntry); - } - categoryEntries.put(catEntry.id, catEntry); - return catEntry.id; - } - - public static void updateCategoryCount(long id) { - CategoryEntry catEntry=categoryEntries.get(id); - if (catEntry==null) { - return; - } - catEntry.count=dbHelper.getCategoryCount(id); - } - - public static void deleteCategoryEntry(long id) { - if (debug) Log.d(TAG,"deleteCategoryEntry("+id+")"); - dbHelper.deleteCategory(id); - categoryEntries.remove(id); - } - - /////////////////////////////////////////////////// - ///////////// Password Functions ////////////////// - /////////////////////////////////////////////////// - - private static void InitPassEntries() { - List passRows; - passRows = dbHelper.fetchAllRows(new Long(0)); - for (PassEntry passRow : passRows) { - passRow.needsDecryptDescription=true; - passRow.needsDecrypt=true; - passRow.needsEncrypt=false; - passEntries.put(passRow.id, passRow); - } - } - - public static List getPassEntries(long categoryId, boolean decrypt, boolean descriptionOnly) { - if (debug) Log.d(TAG,"getPassEntries("+categoryId+","+decrypt+","+descriptionOnly+")"); - Collection passwords=passEntries.values(); - List passList=new ArrayList(); - Iterator passIter=passwords.iterator(); - while (passIter.hasNext()) { - PassEntry passEntry=passIter.next(); - if ((categoryId==0) || (passEntry.category==categoryId)) { - getPassEntry(passEntry.id, decrypt, descriptionOnly); - passList.add(passEntry); - } - } - if (decrypt==true) { - Collections.sort(passList, new Comparator() { - public int compare(PassEntry o1, PassEntry o2) { - return o1.plainDescription.compareToIgnoreCase(o2.plainDescription); - }}); - } - return passList; - } - - public static HashMap getPassIdToDescriptionOLD() { - HashMap passMap = new HashMap(); - Collection passwords=passEntries.values(); - Iterator passIter=passwords.iterator(); - while (passIter.hasNext()) { - PassEntry passEntry=passIter.next(); - // run through and ensure all entries are decrypted - getPassEntry(passEntry.id, true, true); - passMap.put(passEntry.id, passEntry.plainDescription); - } - return passMap; - } - - public static HashMap getPassDescriptionToIdOLD() { - HashMap passMap = new HashMap(); - Collection passwords=passEntries.values(); - Iterator passIter=passwords.iterator(); - while (passIter.hasNext()) { - PassEntry passEntry=passIter.next(); - // run through and ensure all entries are decrypted - getPassEntry(passEntry.id, true, true); - passMap.put(passEntry.plainDescription, passEntry.id); - } - return passMap; - } - - public static PassEntry getPassEntry(Long id, boolean decrypt, boolean descriptionOnly) { - if (debug) Log.d(TAG,"getPassEntry("+id+")"); - if ((id==null) || (passEntries==null)) { - return null; - } - PassEntry passEntry=passEntries.get(id); - if (passEntry==null) { - return null; - } - if (decrypt==false) { - return passEntry; - } - if (passEntry.needsDecryptDescription) { - //if (debug) Log.d(TAG,"decrypt pass description"); - try { - passEntry.plainDescription = ch.decrypt(passEntry.description); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - } - passEntry.needsDecryptDescription=false; - passEntries.put(id, passEntry); - } - if (!descriptionOnly && passEntry.needsDecrypt) { - if (debug) Log.d(TAG,"decrypt pass"); - try { - passEntry.plainDescription = ch.decrypt(passEntry.description); - passEntry.plainWebsite=ch.decrypt(passEntry.website); - passEntry.plainUsername=ch.decrypt(passEntry.username); - passEntry.plainPassword=ch.decrypt(passEntry.password); - passEntry.plainNote=ch.decrypt(passEntry.note); - passEntry.plainUniqueName=ch.decrypt(passEntry.uniqueName); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - } - passEntry.needsDecrypt=false; - passEntries.put(id, passEntry); - } - return passEntry; - } - - public static PassEntry findPassWithUniqueName(String plainUniqueName) { - String uniqueName=""; - try { - uniqueName = ch.encrypt(plainUniqueName); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - return null; - } - Collection passwords=passEntries.values(); - Iterator passIter=passwords.iterator(); - while (passIter.hasNext()) { - PassEntry passEntry=passIter.next(); - if (passEntry.uniqueName.compareTo(uniqueName)==0) { - passEntry=getPassEntry(passEntry.id,true,false); - return passEntry; - } - } - return null; - } - /** - * @param passEntry the entry to placed into the password cache. If id is 0, - * then it will be added, otherwise it will update existing entry. - * @return long row id of newly added or updated entry, - * equal to -1 if a sql error occurred - */ - public static long putPassEntry(PassEntry passEntry) { - if (debug) Log.d(TAG,"putPassEntry("+passEntry.id+")"); - if (passEntry.needsEncrypt) { - if (debug) Log.d(TAG,"encrypt pass"); - try { - passEntry.description = ch.encrypt(passEntry.plainDescription); - passEntry.website = ch.encrypt(passEntry.plainWebsite); - passEntry.username = ch.encrypt(passEntry.plainUsername); - passEntry.password = ch.encrypt(passEntry.plainPassword); - passEntry.note = ch.encrypt(passEntry.plainNote); - passEntry.uniqueName = ch.encrypt(passEntry.plainUniqueName); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - } - passEntry.needsEncrypt=false; - } - // Format the current time. - Date date = new Date(); - DateFormat df = DateFormat.getDateTimeInstance(DateFormat.DEFAULT,DateFormat.LONG); - passEntry.lastEdited=df.format(date); - - if (passEntry.id==0) { - passEntry.id=dbHelper.addPassword(passEntry); - if (passEntry.id==-1) { - // error adding - return -1; - } - updateCategoryCount(passEntry.category); - } else { - long success=dbHelper.updatePassword(passEntry.id, passEntry); - if (success==-1) { - return -1; - } - } - passEntries.put(passEntry.id, passEntry); - return passEntry.id; - } - - public static void deletePassEntry(long id) { - if (debug) Log.d(TAG,"deletePassEntry("+id+")"); - PassEntry passEntry=getPassEntry(id, false, false); - if (passEntry==null) { - return; - } - long categoryId=passEntry.category; - dbHelper.deletePassword(id); - passEntries.remove(id); - updateCategoryCount(categoryId); - } - - public static void updatePassCategory(long passId, long categoryId) { - PassEntry passEntry=passEntries.get(passId); - passEntry.category=categoryId; - dbHelper.updatePasswordCategory(passId, categoryId); - } - - /** - * @param categoryId if -1 then count all passwords - */ - public static int countPasswords(long categoryId) { - return dbHelper.countPasswords(categoryId); - } - - /////////////////////////////////////////////////// - ////////// Package Access Functions /////////////// - /////////////////////////////////////////////////// - - private static void InitPackageAccess() { - HashMap> dbPackageAccess=dbHelper.fetchPackageAccessAll(); - if (!dbPackageAccess.isEmpty()) { - Set keys=dbPackageAccess.keySet(); - Iterator keysIter=keys.iterator(); - while (keysIter.hasNext()) { - Long key=keysIter.next(); - ArrayList packageNames=new ArrayList(); - ArrayList dbPackageNames=dbPackageAccess.get(key); - Iterator packIter=dbPackageNames.iterator(); - while (packIter.hasNext()) { - String packageName=packIter.next(); - PackageAccessEntry packageAccess = new PackageAccessEntry(); - packageAccess.packageAccess=packageName; - packageAccess.needsDecrypt=true; - packageAccess.needsEncrypt=false; - packageNames.add(packageAccess); - } - packageAccessEntries.put(key, packageNames); - } - } - } - - public static ArrayList getPackageAccess(Long id) { - ArrayList packageAccess=null; - if (packageAccessEntries.containsKey(id)) { - ArrayList packageAccessEntry=packageAccessEntries.get(id); - Iterator packIter=packageAccessEntry.iterator(); - packageAccess=new ArrayList(); - while(packIter.hasNext()) { - PackageAccessEntry packEntry=packIter.next(); - if (packEntry.needsDecrypt) { - try { - packEntry.plainPackageAccess=ch.decrypt(packEntry.packageAccess); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - } - } - packageAccess.add(packEntry.plainPackageAccess); - } - } - return packageAccess; - } - - public static ArrayList getPackageAccessEntries(Long id) { - if (packageAccessEntries.containsKey(id)) { - return packageAccessEntries.get(id); - } - return null; - } - - public static void addPackageAccess(Long id, String packageName) { - String encryptedPackageName=""; - try { - encryptedPackageName = ch.encrypt(packageName); - dbHelper.addPackageAccess(id, encryptedPackageName); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - return; - } - - ArrayList packageNames; - if (packageAccessEntries.containsKey(id)) { - packageNames=packageAccessEntries.get(id); - } else { - packageNames=new ArrayList(); - } - PackageAccessEntry newPackageAccessEntry=new PackageAccessEntry(); - newPackageAccessEntry.plainPackageAccess=packageName; - newPackageAccessEntry.packageAccess=encryptedPackageName; - newPackageAccessEntry.needsDecrypt=false; - newPackageAccessEntry.needsEncrypt=false; - packageNames.add(newPackageAccessEntry); - packageAccessEntries.put(id, packageNames); - } + private static final boolean debug = false; + private static final String TAG = "Passwords"; + + private static HashMap passEntries = null; + + private static HashMap categoryEntries = null; + + private static HashMap> packageAccessEntries = null; + + private static CryptoHelper ch = null; + private static boolean cryptoInitialized = false; + + private static DBHelper dbHelper = null; + + public static boolean Initialize(Context ctx) { + if (debug) { + Log.d(TAG, "Initialize()"); + } + + if (ch == null) { + ch = new CryptoHelper(); + } + if ((cryptoInitialized == false) && + (Master.getSalt() != null) && + (Master.getMasterKey() != null)) { + try { + Passwords.InitCrypto( + CryptoHelper.EncryptionMedium, + Master.getSalt(), Master.getMasterKey() + ); + cryptoInitialized = true; + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText( + ctx, "CategoryList: " + ctx.getString(R.string.crypto_error), + Toast.LENGTH_SHORT + ).show(); + } + } + + if (dbHelper == null) { + dbHelper = new DBHelper(ctx); + if (dbHelper.isDatabaseOpen() == false) { + return false; + } + } + if (passEntries == null) { + passEntries = new HashMap(); + InitPassEntries(); + } + if (categoryEntries == null) { + categoryEntries = new HashMap(); + InitCategoryEntries(); + } + if (packageAccessEntries == null) { + packageAccessEntries = new HashMap>(); + InitPackageAccess(); + } + return true; + } + + /** + * Force a fresh load from the database. + */ + public static void Reset() { + categoryEntries.clear(); + InitCategoryEntries(); + passEntries.clear(); + InitPassEntries(); + packageAccessEntries.clear(); + InitPackageAccess(); + } + + public static void InitCrypto(int strength, String salt, String masterKey) + throws Exception { + if (debug) { + Log.d(TAG, "InitCrypto(" + strength + "," + salt + "," + masterKey); + } + try { + ch.init(strength, salt); + ch.setPassword(masterKey); + } catch (CryptoHelperException e1) { + e1.printStackTrace(); + throw new Exception( + "Error with Passwords.InitCrypto: " + + e1.getLocalizedMessage() + ); + } + } + + public static boolean isCryptoInitialized() { + return cryptoInitialized; + } + + public static void deleteAll() { + dbHelper.deleteDatabase(); + Reset(); + } + + public static boolean getPrePopulate() { + return dbHelper.getPrePopulate(); + } + + public static void clearPrePopulate() { + dbHelper.clearPrePopulate(); + } + + public static String fetchSalt() { + return dbHelper.fetchSalt(); + } + + public static String fetchMasterKeyEncrypted() { + return dbHelper.fetchMasterKey(); + } + /////////////////////////////////////////////////// + ///////////// Category Functions ////////////////// + /////////////////////////////////////////////////// + + private static void InitCategoryEntries() { + List catRows; + catRows = dbHelper.fetchAllCategoryRows(); + for (CategoryEntry catRow : catRows) { + catRow.nameNeedsDecrypt = true; + catRow.plainNameNeedsEncrypt = false; + categoryEntries.put(catRow.id, catRow); + } + } + + public static List getCategoryEntries() { + Collection categories = categoryEntries.values(); + Iterator catIter = categories.iterator(); + while (catIter.hasNext()) { + CategoryEntry catEntry = catIter.next(); + // run through and ensure all entries are decrypted + getCategoryEntry(catEntry.id); + } + List catList = new ArrayList(categories); + Collections.sort( + catList, new Comparator() { + public int compare(CategoryEntry o1, CategoryEntry o2) { + return o1.plainName.compareToIgnoreCase(o2.plainName); + } + } + ); + return catList; + } + + public static List getCategoryNames() { + List items = new ArrayList(); + + List catList = getCategoryEntries(); + for (CategoryEntry row : catList) { + items.add(row.plainName); + } + return items; + } + + public static HashMap getCategoryIdToName() { + HashMap categoryMap = new HashMap(); + Collection categories = categoryEntries.values(); + Iterator catIter = categories.iterator(); + while (catIter.hasNext()) { + CategoryEntry catEntry = catIter.next(); + // run through and ensure all entries are decrypted + getCategoryEntry(catEntry.id); + categoryMap.put(catEntry.id, catEntry.plainName); + } + return categoryMap; + } + + public static HashMap getCategoryNameToId() { + HashMap categoryMap = new HashMap(); + Collection categories = categoryEntries.values(); + Iterator catIter = categories.iterator(); + while (catIter.hasNext()) { + CategoryEntry catEntry = catIter.next(); + // run through and ensure all entries are decrypted + getCategoryEntry(catEntry.id); + categoryMap.put(catEntry.plainName, catEntry.id); + if (debug) { + Log.d(TAG, "map " + catEntry.plainName + " to " + catEntry.id); + } + } + return categoryMap; + } + + public static CategoryEntry getCategoryEntryByName(String category) { + Collection categories = categoryEntries.values(); + Iterator catIter = categories.iterator(); + while (catIter.hasNext()) { + CategoryEntry catEntry = catIter.next(); + if (catEntry.name.compareTo(category) == 0) { + return catEntry; + } + } + return null; + } + + public static CategoryEntry getCategoryEntry(Long id) { + CategoryEntry catEntry = categoryEntries.get(id); + if (catEntry == null) { + return null; + } + if (catEntry.nameNeedsDecrypt) { + if (debug) { + Log.d(TAG, "decrypt cat"); + } + try { + catEntry.plainName = ch.decrypt(catEntry.name); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + catEntry.nameNeedsDecrypt = false; + categoryEntries.put(id, catEntry); + } + catEntry.count = dbHelper.getCategoryCount(id); + return catEntry; + } + + public static long putCategoryEntry(CategoryEntry catEntry) { + if (catEntry.plainNameNeedsEncrypt) { + if (debug) { + Log.d(TAG, "encrypt cat"); + } + try { + catEntry.name = ch.encrypt(catEntry.plainName); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + catEntry.plainNameNeedsEncrypt = false; + } + if (catEntry.id == -1) { + catEntry.id = dbHelper.addCategory(catEntry); + } else { + dbHelper.updateCategory(catEntry.id, catEntry); + } + categoryEntries.put(catEntry.id, catEntry); + return catEntry.id; + } + + public static void updateCategoryCount(long id) { + CategoryEntry catEntry = categoryEntries.get(id); + if (catEntry == null) { + return; + } + catEntry.count = dbHelper.getCategoryCount(id); + } + + public static void deleteCategoryEntry(long id) { + if (debug) { + Log.d(TAG, "deleteCategoryEntry(" + id + ")"); + } + dbHelper.deleteCategory(id); + categoryEntries.remove(id); + } + + /////////////////////////////////////////////////// + ///////////// Password Functions ////////////////// + /////////////////////////////////////////////////// + + private static void InitPassEntries() { + List passRows; + passRows = dbHelper.fetchAllRows(new Long(0)); + for (PassEntry passRow : passRows) { + passRow.needsDecryptDescription = true; + passRow.needsDecrypt = true; + passRow.needsEncrypt = false; + passEntries.put(passRow.id, passRow); + } + } + + public static List getPassEntries(long categoryId, boolean decrypt, boolean descriptionOnly) { + if (debug) { + Log.d(TAG, "getPassEntries(" + categoryId + "," + decrypt + "," + descriptionOnly + ")"); + } + Collection passwords = passEntries.values(); + List passList = new ArrayList(); + Iterator passIter = passwords.iterator(); + while (passIter.hasNext()) { + PassEntry passEntry = passIter.next(); + if ((categoryId == 0) || (passEntry.category == categoryId)) { + getPassEntry(passEntry.id, decrypt, descriptionOnly); + passList.add(passEntry); + } + } + if (decrypt == true) { + Collections.sort( + passList, new Comparator() { + public int compare(PassEntry o1, PassEntry o2) { + return o1.plainDescription.compareToIgnoreCase(o2.plainDescription); + } + } + ); + } + return passList; + } + + public static HashMap getPassIdToDescriptionOLD() { + HashMap passMap = new HashMap(); + Collection passwords = passEntries.values(); + Iterator passIter = passwords.iterator(); + while (passIter.hasNext()) { + PassEntry passEntry = passIter.next(); + // run through and ensure all entries are decrypted + getPassEntry(passEntry.id, true, true); + passMap.put(passEntry.id, passEntry.plainDescription); + } + return passMap; + } + + public static HashMap getPassDescriptionToIdOLD() { + HashMap passMap = new HashMap(); + Collection passwords = passEntries.values(); + Iterator passIter = passwords.iterator(); + while (passIter.hasNext()) { + PassEntry passEntry = passIter.next(); + // run through and ensure all entries are decrypted + getPassEntry(passEntry.id, true, true); + passMap.put(passEntry.plainDescription, passEntry.id); + } + return passMap; + } + + public static PassEntry getPassEntry(Long id, boolean decrypt, boolean descriptionOnly) { + if (debug) { + Log.d(TAG, "getPassEntry(" + id + ")"); + } + if ((id == null) || (passEntries == null)) { + return null; + } + PassEntry passEntry = passEntries.get(id); + if (passEntry == null) { + return null; + } + if (decrypt == false) { + return passEntry; + } + if (passEntry.needsDecryptDescription) { + //if (debug) Log.d(TAG,"decrypt pass description"); + try { + passEntry.plainDescription = ch.decrypt(passEntry.description); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + passEntry.needsDecryptDescription = false; + passEntries.put(id, passEntry); + } + if (!descriptionOnly && passEntry.needsDecrypt) { + if (debug) { + Log.d(TAG, "decrypt pass"); + } + try { + passEntry.plainDescription = ch.decrypt(passEntry.description); + passEntry.plainWebsite = ch.decrypt(passEntry.website); + passEntry.plainUsername = ch.decrypt(passEntry.username); + passEntry.plainPassword = ch.decrypt(passEntry.password); + passEntry.plainNote = ch.decrypt(passEntry.note); + passEntry.plainUniqueName = ch.decrypt(passEntry.uniqueName); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + passEntry.needsDecrypt = false; + passEntries.put(id, passEntry); + } + return passEntry; + } + + public static PassEntry findPassWithUniqueName(String plainUniqueName) { + String uniqueName = ""; + try { + uniqueName = ch.encrypt(plainUniqueName); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + return null; + } + Collection passwords = passEntries.values(); + Iterator passIter = passwords.iterator(); + while (passIter.hasNext()) { + PassEntry passEntry = passIter.next(); + if (passEntry.uniqueName.compareTo(uniqueName) == 0) { + passEntry = getPassEntry(passEntry.id, true, false); + return passEntry; + } + } + return null; + } + + /** + * @param passEntry the entry to placed into the password cache. If id is 0, + * then it will be added, otherwise it will update existing entry. + * @return long row id of newly added or updated entry, + * equal to -1 if a sql error occurred + */ + public static long putPassEntry(PassEntry passEntry) { + if (debug) { + Log.d(TAG, "putPassEntry(" + passEntry.id + ")"); + } + if (passEntry.needsEncrypt) { + if (debug) { + Log.d(TAG, "encrypt pass"); + } + try { + passEntry.description = ch.encrypt(passEntry.plainDescription); + passEntry.website = ch.encrypt(passEntry.plainWebsite); + passEntry.username = ch.encrypt(passEntry.plainUsername); + passEntry.password = ch.encrypt(passEntry.plainPassword); + passEntry.note = ch.encrypt(passEntry.plainNote); + passEntry.uniqueName = ch.encrypt(passEntry.plainUniqueName); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + passEntry.needsEncrypt = false; + } + // Format the current time. + Date date = new Date(); + DateFormat df = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.LONG); + passEntry.lastEdited = df.format(date); + + if (passEntry.id == 0) { + passEntry.id = dbHelper.addPassword(passEntry); + if (passEntry.id == -1) { + // error adding + return -1; + } + updateCategoryCount(passEntry.category); + } else { + long success = dbHelper.updatePassword(passEntry.id, passEntry); + if (success == -1) { + return -1; + } + } + passEntries.put(passEntry.id, passEntry); + return passEntry.id; + } + + public static void deletePassEntry(long id) { + if (debug) { + Log.d(TAG, "deletePassEntry(" + id + ")"); + } + PassEntry passEntry = getPassEntry(id, false, false); + if (passEntry == null) { + return; + } + long categoryId = passEntry.category; + dbHelper.deletePassword(id); + passEntries.remove(id); + updateCategoryCount(categoryId); + } + + public static void updatePassCategory(long passId, long categoryId) { + PassEntry passEntry = passEntries.get(passId); + passEntry.category = categoryId; + dbHelper.updatePasswordCategory(passId, categoryId); + } + + /** + * @param categoryId if -1 then count all passwords + */ + public static int countPasswords(long categoryId) { + return dbHelper.countPasswords(categoryId); + } + + /////////////////////////////////////////////////// + ////////// Package Access Functions /////////////// + /////////////////////////////////////////////////// + + private static void InitPackageAccess() { + HashMap> dbPackageAccess = dbHelper.fetchPackageAccessAll(); + if (!dbPackageAccess.isEmpty()) { + Set keys = dbPackageAccess.keySet(); + Iterator keysIter = keys.iterator(); + while (keysIter.hasNext()) { + Long key = keysIter.next(); + ArrayList packageNames = new ArrayList(); + ArrayList dbPackageNames = dbPackageAccess.get(key); + Iterator packIter = dbPackageNames.iterator(); + while (packIter.hasNext()) { + String packageName = packIter.next(); + PackageAccessEntry packageAccess = new PackageAccessEntry(); + packageAccess.packageAccess = packageName; + packageAccess.needsDecrypt = true; + packageAccess.needsEncrypt = false; + packageNames.add(packageAccess); + } + packageAccessEntries.put(key, packageNames); + } + } + } + + public static ArrayList getPackageAccess(Long id) { + ArrayList packageAccess = null; + if (packageAccessEntries.containsKey(id)) { + ArrayList packageAccessEntry = packageAccessEntries.get(id); + Iterator packIter = packageAccessEntry.iterator(); + packageAccess = new ArrayList(); + while (packIter.hasNext()) { + PackageAccessEntry packEntry = packIter.next(); + if (packEntry.needsDecrypt) { + try { + packEntry.plainPackageAccess = ch.decrypt(packEntry.packageAccess); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + } + packageAccess.add(packEntry.plainPackageAccess); + } + } + return packageAccess; + } + + public static ArrayList getPackageAccessEntries(Long id) { + if (packageAccessEntries.containsKey(id)) { + return packageAccessEntries.get(id); + } + return null; + } + + public static void addPackageAccess(Long id, String packageName) { + String encryptedPackageName = ""; + try { + encryptedPackageName = ch.encrypt(packageName); + dbHelper.addPackageAccess(id, encryptedPackageName); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + return; + } + + ArrayList packageNames; + if (packageAccessEntries.containsKey(id)) { + packageNames = packageAccessEntries.get(id); + } else { + packageNames = new ArrayList(); + } + PackageAccessEntry newPackageAccessEntry = new PackageAccessEntry(); + newPackageAccessEntry.plainPackageAccess = packageName; + newPackageAccessEntry.packageAccess = encryptedPackageName; + newPackageAccessEntry.needsDecrypt = false; + newPackageAccessEntry.needsEncrypt = false; + packageNames.add(newPackageAccessEntry); + packageAccessEntries.put(id, packageNames); + } } diff --git a/Safe/src/org/openintents/safe/Preferences.java b/Safe/src/org/openintents/safe/Preferences.java index 864f7c7f..f639ce4a 100644 --- a/Safe/src/org/openintents/safe/Preferences.java +++ b/Safe/src/org/openintents/safe/Preferences.java @@ -1,18 +1,10 @@ package org.openintents.safe; -import java.util.List; - -import org.openintents.distribution.DownloadOIAppDialog; -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.honeycomb.WrapActionBar; - import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; -import android.content.IntentFilter; - import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.PackageManager; @@ -29,176 +21,194 @@ import android.view.MenuItem; import android.widget.Toast; +import java.util.List; + +import org.openintents.distribution.DownloadOIAppDialog; +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.honeycomb.WrapActionBar; + public class Preferences extends PreferenceActivity - implements OnSharedPreferenceChangeListener { + implements OnSharedPreferenceChangeListener { public static final String BACKUP_METHOD_DOCUMENT_PROVIDER = "document_provider"; public static final String BACKUP_METHOD_FILE = "file"; - private static String TAG = "Preferences"; - - public static final String PREFERENCE_ALLOW_EXTERNAL_ACCESS = "external_access"; - public static final String PREFERENCE_LOCK_TIMEOUT = "lock_timeout"; - public static final String PREFERENCE_LOCK_TIMEOUT_DEFAULT_VALUE = "5"; - public static final String PREFERENCE_LOCK_ON_SCREEN_LOCK = "lock_on_screen_lock"; - public static final String PREFERENCE_FIRST_TIME_WARNING = "first_time_warning"; - public static final String PREFERENCE_KEYPAD = "keypad"; - public static final String PREFERENCE_KEYPAD_MUTE = "keypad_mute"; - public static final String PREFERENCE_LAST_BACKUP_JULIAN = "last_backup_julian"; - public static final String PREFERENCE_LAST_AUTOBACKUP_CHECK = "last_autobackup_check"; - public static final String PREFERENCE_AUTOBACKUP = "autobackup"; - public static final String PREFERENCE_AUTOBACKUP_DAYS = "autobackup_days"; - public static final String PREFERENCE_AUTOBACKUP_DAYS_DEFAULT_VALUE = "7"; + private static String TAG = "Preferences"; + + public static final String PREFERENCE_ALLOW_EXTERNAL_ACCESS = "external_access"; + public static final String PREFERENCE_LOCK_TIMEOUT = "lock_timeout"; + public static final String PREFERENCE_LOCK_TIMEOUT_DEFAULT_VALUE = "5"; + public static final String PREFERENCE_LOCK_ON_SCREEN_LOCK = "lock_on_screen_lock"; + public static final String PREFERENCE_FIRST_TIME_WARNING = "first_time_warning"; + public static final String PREFERENCE_KEYPAD = "keypad"; + public static final String PREFERENCE_KEYPAD_MUTE = "keypad_mute"; + public static final String PREFERENCE_LAST_BACKUP_JULIAN = "last_backup_julian"; + public static final String PREFERENCE_LAST_AUTOBACKUP_CHECK = "last_autobackup_check"; + public static final String PREFERENCE_AUTOBACKUP = "autobackup"; + public static final String PREFERENCE_AUTOBACKUP_DAYS = "autobackup_days"; + public static final String PREFERENCE_AUTOBACKUP_DAYS_DEFAULT_VALUE = "7"; public static final String PREFERENCE_BACKUP_PATH = "backup_path"; public static final String PREFERENCE_BACKUP_DOCUMENT = "backup_document"; public static final String PREFERENCE_BACKUP_METHOD = "backup_method"; public static final String PREFERENCE_BACKUP_PATH_DEFAULT_VALUE = - Environment.getExternalStorageDirectory().getAbsolutePath()+"/oisafe.xml"; - public static final String PREFERENCE_EXPORT_PATH = "export_path"; - public static final String PREFERENCE_EXPORT_PATH_DEFAULT_VALUE = - Environment.getExternalStorageDirectory().getAbsolutePath()+"/oisafe.csv"; - - - public static final int REQUEST_BACKUP_FILENAME = 0; + Environment.getExternalStorageDirectory().getAbsolutePath() + "/oisafe.xml"; + public static final String PREFERENCE_EXPORT_PATH = "export_path"; + public static final String PREFERENCE_EXPORT_PATH_DEFAULT_VALUE = + Environment.getExternalStorageDirectory().getAbsolutePath() + "/oisafe.csv"; + + public static final int REQUEST_BACKUP_FILENAME = 0; public static final int REQUEST_BACKUP_DOCUMENT = 1; - public static final int REQUEST_EXPORT_FILENAME = 2; - - public static final int DIALOG_DOWNLOAD_OI_FILEMANAGER = 0; - - Intent frontdoor; - private Intent restartTimerIntent=null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (BuildConfig.DEBUG) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.preferences); - - Preference backupPathPref = findPreference(PREFERENCE_BACKUP_PATH); - backupPathPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference pref){ - Intent intent; - int requestId; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ - intent = Intents.createCreateDocumentIntent(); - requestId = REQUEST_BACKUP_FILENAME; - } else { - intent = Intents.createPickFileIntent(Preferences.getBackupPath(Preferences.this), R.string.backup_select_file); - requestId = REQUEST_BACKUP_FILENAME; + public static final int REQUEST_EXPORT_FILENAME = 2; + + public static final int DIALOG_DOWNLOAD_OI_FILEMANAGER = 0; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (BuildConfig.DEBUG) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); } - if(intentCallable(intent)) - startActivityForResult(intent, requestId ); - else - askForFileManager(); - return false; - } - }); - - Preference exportPathPref = findPreference(PREFERENCE_EXPORT_PATH); - exportPathPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference pref){ - Intent intent = new Intent("org.openintents.action.PICK_FILE"); - intent.setData(Uri.parse("file://"+getExportPath(Preferences.this))); - intent.putExtra("org.openintents.extra.TITLE", R.string.export_file_select); - if(intentCallable(intent)) - startActivityForResult(intent, REQUEST_EXPORT_FILENAME); - else - askForFileManager(); - return false; - } - }); - - - getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); - changePreferenceSummaryToCurrentValue(backupPathPref, getBackupPath(this)); - changePreferenceSummaryToCurrentValue(exportPathPref, getExportPath(this)); - - if(CheckWrappers.mActionBarAvailable){ - WrapActionBar bar = new WrapActionBar(this); - bar.setDisplayHomeAsUpEnabled(true); - } - } + startActivity(frontdoor); + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.preferences); + + Preference backupPathPref = findPreference(PREFERENCE_BACKUP_PATH); + backupPathPref.setOnPreferenceClickListener( + new OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference pref) { + Intent intent; + int requestId; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + intent = Intents.createCreateDocumentIntent(); + requestId = REQUEST_BACKUP_FILENAME; + } else { + intent = Intents.createPickFileIntent(Preferences.getBackupPath(Preferences.this), R.string.backup_select_file); + requestId = REQUEST_BACKUP_FILENAME; + } + if (intentCallable(intent)) { + startActivityForResult(intent, requestId); + } else { + askForFileManager(); + } + return false; + } + } + ); + + Preference exportPathPref = findPreference(PREFERENCE_EXPORT_PATH); + exportPathPref.setOnPreferenceClickListener( + new OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference pref) { + Intent intent = new Intent("org.openintents.action.PICK_FILE"); + intent.setData(Uri.parse("file://" + getExportPath(Preferences.this))); + intent.putExtra("org.openintents.extra.TITLE", R.string.export_file_select); + if (intentCallable(intent)) { + startActivityForResult(intent, REQUEST_EXPORT_FILENAME); + } else { + askForFileManager(); + } + return false; + } + } + ); + + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + changePreferenceSummaryToCurrentValue(backupPathPref, getBackupPath(this)); + changePreferenceSummaryToCurrentValue(exportPathPref, getExportPath(this)); + + if (CheckWrappers.mActionBarAvailable) { + WrapActionBar bar = new WrapActionBar(this); + bar.setDisplayHomeAsUpEnabled(true); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (CategoryList.isSignedIn() == false) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + } @Override - protected void onResume() { - super.onResume(); - - if (CategoryList.isSignedIn()==false) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - } - - @Override - protected void onPause() { - super.onPause(); - - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (BuildConfig.DEBUG) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + protected void onPause() { + super.onPause(); + + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (BuildConfig.DEBUG) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // startActivity(frontdoor); - }else{ - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } - - /** - * Handler for when a MenuItem is selected from the Activity. - */ - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - break; - } - return super.onOptionsItemSelected(item); - } - - static String getBackupPath(Context context){ - return PreferenceManager.getDefaultSharedPreferences(context) - .getString(PREFERENCE_BACKUP_PATH, PREFERENCE_BACKUP_PATH_DEFAULT_VALUE); - } - - static void setBackupPathAndMethod(Context context, String path){ - SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor editor = settings.edit(); - editor.putString(PREFERENCE_BACKUP_PATH, path); + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } + + /** + * Handler for when a MenuItem is selected from the Activity. + */ + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + } + return super.onOptionsItemSelected(item); + } + + static String getBackupPath(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context) + .getString(PREFERENCE_BACKUP_PATH, PREFERENCE_BACKUP_PATH_DEFAULT_VALUE); + } + + static void setBackupPathAndMethod(Context context, String path) { + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor editor = settings.edit(); + editor.putString(PREFERENCE_BACKUP_PATH, path); editor.putString(PREFERENCE_BACKUP_METHOD, BACKUP_METHOD_FILE); - editor.commit(); - } + editor.commit(); + } public static String getBackupDocument(Context context) { return PreferenceManager.getDefaultSharedPreferences(context) .getString(PREFERENCE_BACKUP_DOCUMENT, null); } - static void setBackupDocumentAndMethod(Context context, String uriString){ + + static void setBackupDocumentAndMethod(Context context, String uriString) { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences.Editor editor = settings.edit(); editor.putString(PREFERENCE_BACKUP_DOCUMENT, uriString); @@ -206,97 +216,104 @@ static void setBackupDocumentAndMethod(Context context, String uriString){ editor.commit(); } - private static void setBackupMethod(Context context, String backupMethod) { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences.Editor editor = settings.edit(); editor.putString(PREFERENCE_BACKUP_METHOD, backupMethod); editor.commit(); } - - static String getExportPath(Context context){ - return PreferenceManager.getDefaultSharedPreferences(context) - .getString(PREFERENCE_EXPORT_PATH, PREFERENCE_EXPORT_PATH_DEFAULT_VALUE); - } - - static void setExportPath(Context context, String path){ - SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor editor = settings.edit(); - editor.putString(PREFERENCE_EXPORT_PATH, path); - editor.commit(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent i) { - switch(requestCode){ - case REQUEST_BACKUP_FILENAME: - if(resultCode == RESULT_OK) { - setBackupPathAndMethod(this, i.getData().getPath()); - setBackupMethod(this, BACKUP_METHOD_FILE); - } - break; - case REQUEST_BACKUP_DOCUMENT: - if(resultCode == RESULT_OK) { - setBackupPathAndMethod(this, i.getData().getPath()); - setBackupMethod(this, BACKUP_METHOD_DOCUMENT_PROVIDER); - } - break; - - - case REQUEST_EXPORT_FILENAME: - if(resultCode == RESULT_OK) - setExportPath(this, i.getData().getPath()); - break; - } - } - - private boolean intentCallable(Intent intent){ - List list = getPackageManager().queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - return list.size() > 0; - } - - private void askForFileManager(){ - Toast.makeText(this, R.string.download_oi_filemanager, Toast.LENGTH_LONG).show(); - showDialog(DIALOG_DOWNLOAD_OI_FILEMANAGER); - } - - @Override - protected Dialog onCreateDialog(int id) { - Dialog d = super.onCreateDialog(id); - switch(id) { - case DIALOG_DOWNLOAD_OI_FILEMANAGER: - d = new DownloadOIAppDialog(this, - DownloadOIAppDialog.OI_FILEMANAGER); - break; - } - return d; - } - - @Override - protected void onPrepareDialog(int id, Dialog dialog) { - super.onPrepareDialog(id, dialog); - - switch (id) { - case DIALOG_DOWNLOAD_OI_FILEMANAGER: - DownloadOIAppDialog.onPrepareDialog(this, dialog); - break; - } - } - - private void changePreferenceSummaryToCurrentValue(Preference pref, String value){ - pref.setSummary(value); - } - - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) { - if(key.equals(PREFERENCE_BACKUP_PATH)) - changePreferenceSummaryToCurrentValue(findPreference(PREFERENCE_BACKUP_PATH), - getBackupPath(this)); - else if(key.equals(PREFERENCE_EXPORT_PATH)) - changePreferenceSummaryToCurrentValue(findPreference(PREFERENCE_EXPORT_PATH), - getExportPath(this)); - } + static String getExportPath(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context) + .getString(PREFERENCE_EXPORT_PATH, PREFERENCE_EXPORT_PATH_DEFAULT_VALUE); + } + + static void setExportPath(Context context, String path) { + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor editor = settings.edit(); + editor.putString(PREFERENCE_EXPORT_PATH, path); + editor.commit(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent i) { + switch (requestCode) { + case REQUEST_BACKUP_FILENAME: + if (resultCode == RESULT_OK) { + setBackupPathAndMethod(this, i.getData().getPath()); + setBackupMethod(this, BACKUP_METHOD_FILE); + } + break; + case REQUEST_BACKUP_DOCUMENT: + if (resultCode == RESULT_OK) { + setBackupPathAndMethod(this, i.getData().getPath()); + setBackupMethod(this, BACKUP_METHOD_DOCUMENT_PROVIDER); + } + break; + + case REQUEST_EXPORT_FILENAME: + if (resultCode == RESULT_OK) { + setExportPath(this, i.getData().getPath()); + } + break; + } + } + + private boolean intentCallable(Intent intent) { + List list = getPackageManager().queryIntentActivities( + intent, + PackageManager.MATCH_DEFAULT_ONLY + ); + return list.size() > 0; + } + + private void askForFileManager() { + Toast.makeText(this, R.string.download_oi_filemanager, Toast.LENGTH_LONG).show(); + showDialog(DIALOG_DOWNLOAD_OI_FILEMANAGER); + } + + @Override + protected Dialog onCreateDialog(int id) { + Dialog d = super.onCreateDialog(id); + switch (id) { + case DIALOG_DOWNLOAD_OI_FILEMANAGER: + d = new DownloadOIAppDialog( + this, + DownloadOIAppDialog.OI_FILEMANAGER + ); + break; + } + return d; + } + + @Override + protected void onPrepareDialog(int id, Dialog dialog) { + super.onPrepareDialog(id, dialog); + + switch (id) { + case DIALOG_DOWNLOAD_OI_FILEMANAGER: + DownloadOIAppDialog.onPrepareDialog(this, dialog); + break; + } + } + + private void changePreferenceSummaryToCurrentValue(Preference pref, String value) { + pref.setSummary(value); + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(PREFERENCE_BACKUP_PATH)) { + changePreferenceSummaryToCurrentValue( + findPreference(PREFERENCE_BACKUP_PATH), + getBackupPath(this) + ); + } else if (key.equals(PREFERENCE_EXPORT_PATH)) { + changePreferenceSummaryToCurrentValue( + findPreference(PREFERENCE_EXPORT_PATH), + getExportPath(this) + ); + } + } } diff --git a/Safe/src/org/openintents/safe/Restore.java b/Safe/src/org/openintents/safe/Restore.java index 0a33699d..2f8ea66a 100644 --- a/Safe/src/org/openintents/safe/Restore.java +++ b/Safe/src/org/openintents/safe/Restore.java @@ -16,21 +16,6 @@ */ package org.openintents.safe; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.List; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.password.Master; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; - import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -55,35 +40,50 @@ import android.widget.TextView; import android.widget.Toast; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.password.Master; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + import butterknife.ButterKnife; import butterknife.InjectView; public class Restore extends Activity { - private static final String TAG = "Restore"; + private static final String TAG = "Restore"; + + private DBHelper dbHelper = null; + private String masterKey = ""; + private RestoreDataSet restoreDataSet = null; + private boolean firstTime = false; - private DBHelper dbHelper=null; - private String masterKey=""; - private RestoreDataSet restoreDataSet=null; - private boolean firstTime=false; + public static final String KEY_FIRST_TIME = "first_time"; // Intent keys + public static final String KEY_FILE_PATH = "backup_file_path"; - public static final String KEY_FIRST_TIME = "first_time"; // Intent keys - public static final String KEY_FILE_PATH = "backup_file_path"; - - public static final int REQUEST_RESTORE_FILENAME = 0; + public static final int REQUEST_RESTORE_FILENAME = 0; public static final int REQUEST_RESTORE_DOCUMENT = 1; - Intent frontdoor; - private Intent restartTimerIntent=null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (BuildConfig.DEBUG) Log.d(TAG,"caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { + if (BuildConfig.DEBUG) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; @InjectView(R.id.restore_filename) TextView filenameText; @InjectView(R.id.restore_info) @@ -94,51 +94,53 @@ public void onReceive(Context context, Intent intent) { Button restoreButton; @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); + public void onCreate(Bundle icicle) { + super.onCreate(icicle); - if (BuildConfig.DEBUG) Log.d(TAG,"onCreate()"); + if (BuildConfig.DEBUG) { + Log.d(TAG, "onCreate()"); + } - firstTime = icicle != null ? icicle.getBoolean(Restore.KEY_FIRST_TIME) : false; - if (firstTime == false) { - Bundle extras = getIntent().getExtras(); - firstTime = extras != null ? extras.getBoolean(Restore.KEY_FIRST_TIME) : false; - } + firstTime = icicle != null ? icicle.getBoolean(Restore.KEY_FIRST_TIME) : false; + if (firstTime == false) { + Bundle extras = getIntent().getExtras(); + firstTime = extras != null ? extras.getBoolean(Restore.KEY_FIRST_TIME) : false; + } - frontdoor = new Intent(this, Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + frontdoor = new Intent(this, Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); - Passwords.Initialize(this); + Passwords.Initialize(this); - setContentView(R.layout.restore); + setContentView(R.layout.restore); ButterKnife.inject(this); - String title = getResources().getString(R.string.app_name) + " - " + - getResources().getString(R.string.restore); - setTitle(title); - - String backupPath = getIntent().getStringExtra(KEY_FILE_PATH); - if (backupPath != null) { + String title = getResources().getString(R.string.app_name) + " - " + + getResources().getString(R.string.restore); + setTitle(title); + + String backupPath = getIntent().getStringExtra(KEY_FILE_PATH); + if (backupPath != null) { restoreFromFile(backupPath); - } else { - backupPath = Preferences.getBackupPath(this); + } else { + backupPath = Preferences.getBackupPath(this); Intent intent; int requestId; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { intent = Intents.createOpenDocumentIntents(Preferences.getBackupDocument(this)); requestId = REQUEST_RESTORE_DOCUMENT; } else { intent = Intents.createPickFileIntent(backupPath, R.string.restore_select_file); requestId = REQUEST_RESTORE_FILENAME; } - if (intentCallable(intent)) - startActivityForResult(intent, requestId); - else { + if (intentCallable(intent)) { + startActivityForResult(intent, requestId); + } else { restoreFromFile(backupPath); } - } - } + } + } private void restoreFromFile(String backupPath) { filenameText.setText(backupPath); @@ -152,230 +154,278 @@ private void restoreFromFile(String backupPath) { } @Override - protected void onPause() { - super.onPause(); - - try { - unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - //if (BuildConfig.DEBUG) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (BuildConfig.DEBUG) Log.d(TAG,"onResume()"); - - if ((!firstTime) && (CategoryList.isSignedIn()==false)) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - registerReceiver(mIntentReceiver, filter); - } - - - public boolean read(InputStreamData streamData, String masterPassword) { - if (BuildConfig.DEBUG) Log.d(TAG,"read("+streamData.getFilename()+",)"); - - SAXParserFactory spf = SAXParserFactory.newInstance(); - try { - SAXParser sp = spf.newSAXParser(); - - XMLReader xr = sp.getXMLReader(); - - RestoreHandler myRestoreHandler = new RestoreHandler(); - xr.setContentHandler(myRestoreHandler); - - xr.parse(new InputSource(streamData.getStream())); - - restoreDataSet = myRestoreHandler.getParsedData(); - - } catch (ParserConfigurationException e) { - //e.printStackTrace(); - Toast.makeText(Restore.this, getString(R.string.restore_unable_to_open, - e.getLocalizedMessage()), - Toast.LENGTH_LONG).show(); - return false; - } catch (SAXException e) { - //e.printStackTrace(); - Toast.makeText(Restore.this, getString(R.string.restore_unable_to_open, - e.getLocalizedMessage()), - Toast.LENGTH_LONG).show(); - return false; - } catch (IOException e) { - //e.printStackTrace(); - Toast.makeText(Restore.this, getString(R.string.restore_unable_to_open, - e.getLocalizedMessage()), - Toast.LENGTH_LONG).show(); - return false; - } - - if (restoreDataSet.getVersion() != Backup.CURRENT_VERSION) { - Toast.makeText(Restore.this, getString(R.string.restore_bad_version, - Integer.toString(restoreDataSet.getVersion())), - Toast.LENGTH_LONG).show(); - return false; - } - CategoryEntry firstCatEntry= null; - if (restoreDataSet.getCategories().size() > 0) { - firstCatEntry = restoreDataSet.getCategories().get(0); - if (firstCatEntry==null) { - Toast.makeText(Restore.this, getString(R.string.restore_error), - Toast.LENGTH_LONG).show(); - return false; - } - } - CryptoHelper ch=new CryptoHelper(); - - String salt=restoreDataSet.getSalt(); - String masterKeyEncrypted=restoreDataSet.getMasterKeyEncrypted(); - masterKey=""; - try { - ch.init(CryptoHelper.EncryptionStrong, salt); - ch.setPassword(masterPassword); - masterKey = ch.decrypt(masterKeyEncrypted); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - Toast.makeText(this, getString(R.string.crypto_error) - + e.getMessage(), Toast.LENGTH_SHORT).show(); - return false; - } - if (ch.getStatus()==false) { - Toast.makeText(Restore.this, getString(R.string.restore_decrypt_error), - Toast.LENGTH_LONG).show(); - Animation shake = AnimationUtils - .loadAnimation(Restore.this, R.anim.shake); - findViewById(R.id.restore_password).startAnimation(shake); - - return false; - } - ch=new CryptoHelper(); - try { - ch.init(CryptoHelper.EncryptionMedium, salt); - ch.setPassword(masterKey); - } catch (CryptoHelperException e1) { - e1.printStackTrace(); - Toast.makeText(this, getString(R.string.crypto_error) - + e1.getMessage(), Toast.LENGTH_SHORT).show(); - return false; - } - - if (firstCatEntry != null) { - String firstCategory=""; - try { - firstCategory = ch.decrypt(firstCatEntry.name); - } catch (CryptoHelperException e) { - Log.e(TAG,e.toString()); - } - if (ch.getStatus() == false) { - Toast.makeText(Restore.this, getString(R.string.restore_decrypt_error), - Toast.LENGTH_LONG).show(); - return false; - } - if (BuildConfig.DEBUG) Log.d(TAG,"firstCategory="+firstCategory); - } - - dbHelper=new DBHelper(Restore.this); - - String msg=getString(R.string.restore_found, - Integer.toString(restoreDataSet.getTotalEntries()), - restoreDataSet.getDate()) - +"\n"+ - getString(R.string.dialog_restore_database_msg); - Dialog confirm = new AlertDialog.Builder(Restore.this) - .setIcon(android.R.drawable.ic_menu_manage) - .setTitle(R.string.dialog_restore_database_title) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - restoreDatabase(); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - dbHelper.close(); - } - }) - .setMessage(msg) - .create(); - confirm.show(); - - return true; - } - - private void restoreDatabase() { - dbHelper.beginTransaction(); - dbHelper.deleteDatabase(); - - dbHelper.storeSalt(restoreDataSet.getSalt()); - dbHelper.storeMasterKey(restoreDataSet.getMasterKeyEncrypted()); - Master.setSalt(restoreDataSet.getSalt()); - Master.setMasterKey(masterKey); - for (CategoryEntry category : restoreDataSet.getCategories()) { - if (BuildConfig.DEBUG) Log.d(TAG,"category="+category.name); - dbHelper.addCategory(category); - } - int totalPasswords=0; - for (PassEntry password : restoreDataSet.getPass()) { - totalPasswords++; - long rowid=dbHelper.addPassword(password); - if (password.packageAccess!=null) { - for (String packageName : password.packageAccess) { - if (BuildConfig.DEBUG) Log.d(TAG,"packageName="+packageName); - dbHelper.addPackageAccess(rowid, packageName); - } - } - } - dbHelper.commit(); - dbHelper.close(); - Passwords.Reset(); - - Toast.makeText(Restore.this, getString(R.string.restore_complete, - Integer.toString(totalPasswords)), - Toast.LENGTH_LONG).show(); - - - // Don't need to show warning anymore to back up, because user has used - // restore already. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(Preferences.PREFERENCE_FIRST_TIME_WARNING, true); - editor.commit(); - - setResult(RESULT_OK); - finish(); - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - - if (BuildConfig.DEBUG) Log.d(TAG,"onUserInteraction()"); - - if (CategoryList.isSignedIn()==false) { + protected void onPause() { + super.onPause(); + + try { + unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + //if (BuildConfig.DEBUG) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (BuildConfig.DEBUG) { + Log.d(TAG, "onResume()"); + } + + if ((!firstTime) && (CategoryList.isSignedIn() == false)) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + registerReceiver(mIntentReceiver, filter); + } + + public boolean read(InputStreamData streamData, String masterPassword) { + if (BuildConfig.DEBUG) { + Log.d(TAG, "read(" + streamData.getFilename() + ",)"); + } + + SAXParserFactory spf = SAXParserFactory.newInstance(); + try { + SAXParser sp = spf.newSAXParser(); + + XMLReader xr = sp.getXMLReader(); + + RestoreHandler myRestoreHandler = new RestoreHandler(); + xr.setContentHandler(myRestoreHandler); + + xr.parse(new InputSource(streamData.getStream())); + + restoreDataSet = myRestoreHandler.getParsedData(); + + } catch (ParserConfigurationException e) { + //e.printStackTrace(); + Toast.makeText( + Restore.this, getString( + R.string.restore_unable_to_open, + e.getLocalizedMessage() + ), + Toast.LENGTH_LONG + ).show(); + return false; + } catch (SAXException e) { + //e.printStackTrace(); + Toast.makeText( + Restore.this, getString( + R.string.restore_unable_to_open, + e.getLocalizedMessage() + ), + Toast.LENGTH_LONG + ).show(); + return false; + } catch (IOException e) { + //e.printStackTrace(); + Toast.makeText( + Restore.this, getString( + R.string.restore_unable_to_open, + e.getLocalizedMessage() + ), + Toast.LENGTH_LONG + ).show(); + return false; + } + + if (restoreDataSet.getVersion() != Backup.CURRENT_VERSION) { + Toast.makeText( + Restore.this, getString( + R.string.restore_bad_version, + Integer.toString(restoreDataSet.getVersion()) + ), + Toast.LENGTH_LONG + ).show(); + return false; + } + CategoryEntry firstCatEntry = null; + if (restoreDataSet.getCategories().size() > 0) { + firstCatEntry = restoreDataSet.getCategories().get(0); + if (firstCatEntry == null) { + Toast.makeText( + Restore.this, getString(R.string.restore_error), + Toast.LENGTH_LONG + ).show(); + return false; + } + } + CryptoHelper ch = new CryptoHelper(); + + String salt = restoreDataSet.getSalt(); + String masterKeyEncrypted = restoreDataSet.getMasterKeyEncrypted(); + masterKey = ""; + try { + ch.init(CryptoHelper.EncryptionStrong, salt); + ch.setPassword(masterPassword); + masterKey = ch.decrypt(masterKeyEncrypted); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + Toast.makeText( + this, getString(R.string.crypto_error) + + e.getMessage(), Toast.LENGTH_SHORT + ).show(); + return false; + } + if (ch.getStatus() == false) { + Toast.makeText( + Restore.this, getString(R.string.restore_decrypt_error), + Toast.LENGTH_LONG + ).show(); + Animation shake = AnimationUtils + .loadAnimation(Restore.this, R.anim.shake); + findViewById(R.id.restore_password).startAnimation(shake); + + return false; + } + ch = new CryptoHelper(); + try { + ch.init(CryptoHelper.EncryptionMedium, salt); + ch.setPassword(masterKey); + } catch (CryptoHelperException e1) { + e1.printStackTrace(); + Toast.makeText( + this, getString(R.string.crypto_error) + + e1.getMessage(), Toast.LENGTH_SHORT + ).show(); + return false; + } + + if (firstCatEntry != null) { + String firstCategory = ""; + try { + firstCategory = ch.decrypt(firstCatEntry.name); + } catch (CryptoHelperException e) { + Log.e(TAG, e.toString()); + } + if (ch.getStatus() == false) { + Toast.makeText( + Restore.this, getString(R.string.restore_decrypt_error), + Toast.LENGTH_LONG + ).show(); + return false; + } + if (BuildConfig.DEBUG) { + Log.d(TAG, "firstCategory=" + firstCategory); + } + } + + dbHelper = new DBHelper(Restore.this); + + String msg = getString( + R.string.restore_found, + Integer.toString(restoreDataSet.getTotalEntries()), + restoreDataSet.getDate() + ) + + "\n" + + getString(R.string.dialog_restore_database_msg); + Dialog confirm = new AlertDialog.Builder(Restore.this) + .setIcon(android.R.drawable.ic_menu_manage) + .setTitle(R.string.dialog_restore_database_title) + .setPositiveButton( + R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + restoreDatabase(); + } + } + ) + .setNegativeButton( + R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + dbHelper.close(); + } + } + ) + .setMessage(msg) + .create(); + confirm.show(); + + return true; + } + + private void restoreDatabase() { + dbHelper.beginTransaction(); + dbHelper.deleteDatabase(); + + dbHelper.storeSalt(restoreDataSet.getSalt()); + dbHelper.storeMasterKey(restoreDataSet.getMasterKeyEncrypted()); + Master.setSalt(restoreDataSet.getSalt()); + Master.setMasterKey(masterKey); + for (CategoryEntry category : restoreDataSet.getCategories()) { + if (BuildConfig.DEBUG) { + Log.d(TAG, "category=" + category.name); + } + dbHelper.addCategory(category); + } + int totalPasswords = 0; + for (PassEntry password : restoreDataSet.getPass()) { + totalPasswords++; + long rowid = dbHelper.addPassword(password); + if (password.packageAccess != null) { + for (String packageName : password.packageAccess) { + if (BuildConfig.DEBUG) { + Log.d(TAG, "packageName=" + packageName); + } + dbHelper.addPackageAccess(rowid, packageName); + } + } + } + dbHelper.commit(); + dbHelper.close(); + Passwords.Reset(); + + Toast.makeText( + Restore.this, getString( + R.string.restore_complete, + Integer.toString(totalPasswords) + ), + Toast.LENGTH_LONG + ).show(); + + // Don't need to show warning anymore to back up, because user has used + // restore already. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(Preferences.PREFERENCE_FIRST_TIME_WARNING, true); + editor.commit(); + + setResult(RESULT_OK); + finish(); + } + + @Override + public void onUserInteraction() { + super.onUserInteraction(); + + if (BuildConfig.DEBUG) { + Log.d(TAG, "onUserInteraction()"); + } + + if (CategoryList.isSignedIn() == false) { // startActivity(frontdoor); - } else { - if (restartTimerIntent!=null) sendBroadcast (restartTimerIntent); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent i){ - super.onActivityResult(requestCode, resultCode, i); - switch(requestCode){ - case REQUEST_RESTORE_FILENAME: - if(resultCode == RESULT_OK){ - String path = i.getData().getPath(); - restoreFromFile(path); - } else{ - setResult(RESULT_CANCELED); - finish(); - } - break; + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + switch (requestCode) { + case REQUEST_RESTORE_FILENAME: + if (resultCode == RESULT_OK) { + String path = i.getData().getPath(); + restoreFromFile(path); + } else { + setResult(RESULT_CANCELED); + finish(); + } + break; case REQUEST_RESTORE_DOCUMENT: - if(resultCode == RESULT_OK){ + if (resultCode == RESULT_OK) { Uri documentUri = i.getData(); filenameText.setText(i.getDataString()); try { @@ -385,12 +435,12 @@ protected void onActivityResult(int requestCode, int resultCode, Intent i){ } catch (FileNotFoundException e) { updateNoRestoreFileUI(); } - } else{ + } else { setResult(RESULT_CANCELED); finish(); } - } - } + } + } private void updateNoRestoreFileUI() { passwordText.setVisibility(View.INVISIBLE); @@ -398,28 +448,31 @@ private void updateNoRestoreFileUI() { restoreInfoText.setText(R.string.restore_no_file); } - private void restore(final InputStreamData inputStreamData){ - - restoreInfoText.setText(R.string.restore_set_password); - passwordText.setVisibility(View.VISIBLE); - restoreButton.setVisibility(View.VISIBLE); - - restoreButton.setOnClickListener(new View.OnClickListener() { - - public void onClick(View arg0) { - EditText passwordText; - passwordText = (EditText) findViewById(R.id.restore_password); - - String masterPassword = passwordText.getText().toString(); - read(inputStreamData, masterPassword); - } - }); - } - - - private boolean intentCallable(Intent intent){ - List list = getPackageManager().queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - return list.size() > 0; - } + private void restore(final InputStreamData inputStreamData) { + + restoreInfoText.setText(R.string.restore_set_password); + passwordText.setVisibility(View.VISIBLE); + restoreButton.setVisibility(View.VISIBLE); + + restoreButton.setOnClickListener( + new View.OnClickListener() { + + public void onClick(View arg0) { + EditText passwordText; + passwordText = (EditText) findViewById(R.id.restore_password); + + String masterPassword = passwordText.getText().toString(); + read(inputStreamData, masterPassword); + } + } + ); + } + + private boolean intentCallable(Intent intent) { + List list = getPackageManager().queryIntentActivities( + intent, + PackageManager.MATCH_DEFAULT_ONLY + ); + return list.size() > 0; + } } diff --git a/Safe/src/org/openintents/safe/RestoreDataSet.java b/Safe/src/org/openintents/safe/RestoreDataSet.java index 67c74914..4a526bde 100644 --- a/Safe/src/org/openintents/safe/RestoreDataSet.java +++ b/Safe/src/org/openintents/safe/RestoreDataSet.java @@ -16,154 +16,192 @@ */ package org.openintents.safe; +import android.util.Log; + import java.util.ArrayList; import java.util.Arrays; -import android.util.Log; - public class RestoreDataSet { - private static boolean debug = false; - private static final String TAG = "RestoreDataSet"; - - private int version = 0; - private String date = null; - private String salt = null; - private String masterKeyEncrypted = null; - private Long currentCategoryId = new Long(0); - private CategoryEntry currentCategory = null; - private ArrayList categoryEntries = new ArrayList(); - private PassEntry currentEntry = null; - private String currentRowID; - private String currentPackageAccess; - private ArrayList passEntries = new ArrayList(); - private int totalEntries = 0; - - public int getVersion() { - return version; - } - public void setVersion(int extractedVersion) { - version = extractedVersion; - } - public String getDate() { - return date; - } - public void setDate(String extractedDate) { - date = extractedDate; - } - public String getSalt() { - return salt; - } - public void setSalt(String extractedSalt) { - salt = extractedSalt; - } - public String getMasterKeyEncrypted() { - return masterKeyEncrypted; - } - public void setMasterKeyEncrypted(String extractedKey) { - masterKeyEncrypted = extractedKey; - } - public ArrayList getCategories() { - return categoryEntries; - } - public void newCategory(String extractedCategory) { - currentCategory = new CategoryEntry(); - currentCategoryId++; - currentCategory.id = currentCategoryId; - currentCategory.name = extractedCategory; - } - public void storyCategory() { - if (currentCategory != null) { - categoryEntries.add(currentCategory); - currentCategory=null; - } - } - public ArrayList getPass() { - return passEntries; - } - public void newEntry() { - currentEntry = new PassEntry(); - currentEntry.category = currentCategoryId; - currentRowID=""; - currentEntry.description=""; - currentEntry.website=""; - currentEntry.username=""; - currentEntry.password=""; - currentEntry.note=""; - currentEntry.uniqueName=""; - currentEntry.packageAccess=null; - currentPackageAccess=""; - } - public void storeEntry() { - // only add an entry if we had all the fields - if (debug) Log.d(TAG,currentEntry.description+" "+currentEntry.website+" "+ - currentEntry.username+" "+currentEntry.password+" "+ - currentEntry.note+" "+currentPackageAccess); - if ((currentEntry != null) && - (currentEntry.description!="")) { - try { - currentEntry.id=Long.parseLong(currentRowID); - } catch (NumberFormatException e) { - currentEntry.id=0; - } - if (currentPackageAccess!="") { - // strip the brackets [ and ] - String packageList = currentPackageAccess.substring(1, - currentPackageAccess.length()-1); - String[] packages = packageList.split(","); - currentEntry.packageAccess=new ArrayList(Arrays.asList(packages)); - if (debug) Log.d(TAG,"packageAccess="+currentEntry.packageAccess.toString()); - } - passEntries.add(currentEntry); - totalEntries++; - } - currentEntry = null; - } - public int getTotalEntries() { - return totalEntries; - } - public void setRowID(String extractedRowID) { - if (debug) Log.d(TAG,"setRowID("+extractedRowID+")"); - if (currentEntry != null) { - currentRowID += extractedRowID; - } - } - public void setDescription(String extractedDescription) { - if (debug) Log.d(TAG,"setDescription("+extractedDescription+")"); - if (currentEntry != null) { - currentEntry.description += extractedDescription; - } - } - public void setWebsite(String extractedWebsite) { - if (debug) Log.d(TAG,"setWebsite("+extractedWebsite+")"); - if (currentEntry != null) { - currentEntry.website += extractedWebsite; - } - } - public void setUsername(String extractedUsername) { - if (currentEntry != null) { - currentEntry.username += extractedUsername; - } - } - public void setPassword(String extractedPassword) { - if (currentEntry != null) { - currentEntry.password += extractedPassword; - } - } - public void setNote(String extractedNote) { - if (currentEntry != null) { - currentEntry.note += extractedNote; - } - } - public void setUniqueName(String extractedUniqueName) { - if (currentEntry != null) { - currentEntry.uniqueName += extractedUniqueName; - } - } - public void setPackageAccess(String extractedPackageAccess) { - if (debug) Log.d(TAG,"setPackageAccess("+extractedPackageAccess+")"); - if (currentPackageAccess != null) { - currentPackageAccess += extractedPackageAccess; - } - } + private static boolean debug = false; + private static final String TAG = "RestoreDataSet"; + + private int version = 0; + private String date = null; + private String salt = null; + private String masterKeyEncrypted = null; + private Long currentCategoryId = new Long(0); + private CategoryEntry currentCategory = null; + private ArrayList categoryEntries = new ArrayList(); + private PassEntry currentEntry = null; + private String currentRowID; + private String currentPackageAccess; + private ArrayList passEntries = new ArrayList(); + private int totalEntries = 0; + + public int getVersion() { + return version; + } + + public void setVersion(int extractedVersion) { + version = extractedVersion; + } + + public String getDate() { + return date; + } + + public void setDate(String extractedDate) { + date = extractedDate; + } + + public String getSalt() { + return salt; + } + + public void setSalt(String extractedSalt) { + salt = extractedSalt; + } + + public String getMasterKeyEncrypted() { + return masterKeyEncrypted; + } + + public void setMasterKeyEncrypted(String extractedKey) { + masterKeyEncrypted = extractedKey; + } + + public ArrayList getCategories() { + return categoryEntries; + } + + public void newCategory(String extractedCategory) { + currentCategory = new CategoryEntry(); + currentCategoryId++; + currentCategory.id = currentCategoryId; + currentCategory.name = extractedCategory; + } + + public void storyCategory() { + if (currentCategory != null) { + categoryEntries.add(currentCategory); + currentCategory = null; + } + } + + public ArrayList getPass() { + return passEntries; + } + + public void newEntry() { + currentEntry = new PassEntry(); + currentEntry.category = currentCategoryId; + currentRowID = ""; + currentEntry.description = ""; + currentEntry.website = ""; + currentEntry.username = ""; + currentEntry.password = ""; + currentEntry.note = ""; + currentEntry.uniqueName = ""; + currentEntry.packageAccess = null; + currentPackageAccess = ""; + } + + public void storeEntry() { + // only add an entry if we had all the fields + if (debug) { + Log.d( + TAG, currentEntry.description + " " + currentEntry.website + " " + + currentEntry.username + " " + currentEntry.password + " " + + currentEntry.note + " " + currentPackageAccess + ); + } + if ((currentEntry != null) && + (currentEntry.description != "")) { + try { + currentEntry.id = Long.parseLong(currentRowID); + } catch (NumberFormatException e) { + currentEntry.id = 0; + } + if (currentPackageAccess != "") { + // strip the brackets [ and ] + String packageList = currentPackageAccess.substring( + 1, + currentPackageAccess.length() - 1 + ); + String[] packages = packageList.split(","); + currentEntry.packageAccess = new ArrayList(Arrays.asList(packages)); + if (debug) { + Log.d(TAG, "packageAccess=" + currentEntry.packageAccess.toString()); + } + } + passEntries.add(currentEntry); + totalEntries++; + } + currentEntry = null; + } + + public int getTotalEntries() { + return totalEntries; + } + + public void setRowID(String extractedRowID) { + if (debug) { + Log.d(TAG, "setRowID(" + extractedRowID + ")"); + } + if (currentEntry != null) { + currentRowID += extractedRowID; + } + } + + public void setDescription(String extractedDescription) { + if (debug) { + Log.d(TAG, "setDescription(" + extractedDescription + ")"); + } + if (currentEntry != null) { + currentEntry.description += extractedDescription; + } + } + + public void setWebsite(String extractedWebsite) { + if (debug) { + Log.d(TAG, "setWebsite(" + extractedWebsite + ")"); + } + if (currentEntry != null) { + currentEntry.website += extractedWebsite; + } + } + + public void setUsername(String extractedUsername) { + if (currentEntry != null) { + currentEntry.username += extractedUsername; + } + } + + public void setPassword(String extractedPassword) { + if (currentEntry != null) { + currentEntry.password += extractedPassword; + } + } + + public void setNote(String extractedNote) { + if (currentEntry != null) { + currentEntry.note += extractedNote; + } + } + + public void setUniqueName(String extractedUniqueName) { + if (currentEntry != null) { + currentEntry.uniqueName += extractedUniqueName; + } + } + + public void setPackageAccess(String extractedPackageAccess) { + if (debug) { + Log.d(TAG, "setPackageAccess(" + extractedPackageAccess + ")"); + } + if (currentPackageAccess != null) { + currentPackageAccess += extractedPackageAccess; + } + } } diff --git a/Safe/src/org/openintents/safe/RestoreFirstTime.java b/Safe/src/org/openintents/safe/RestoreFirstTime.java index ee5ab86f..8377c653 100644 --- a/Safe/src/org/openintents/safe/RestoreFirstTime.java +++ b/Safe/src/org/openintents/safe/RestoreFirstTime.java @@ -1,7 +1,5 @@ package org.openintents.safe; -import org.openintents.util.VersionUtils; - import android.app.Activity; import android.content.Intent; import android.os.Bundle; @@ -10,53 +8,59 @@ import android.widget.Button; import android.widget.TextView; +import org.openintents.util.VersionUtils; + public class RestoreFirstTime extends Activity { - private Button restore; - private Button cancel; - private String path; - - private static final int REQUEST_RESTORE = 0; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.restore_first_time); - path = Preferences.getBackupPath(this); - restore = (Button) findViewById(R.id.restore); - cancel = (Button) findViewById(R.id.cancel); - - ((TextView) findViewById(R.id.filename)).setText(path); - restore.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - Intent i = new Intent(RestoreFirstTime.this, Restore.class); - i.putExtra(Restore.KEY_FILE_PATH, path); - i.putExtra(Restore.KEY_FIRST_TIME, true); - startActivityForResult(i, REQUEST_RESTORE); - } - }); - cancel.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - setResult(RESULT_CANCELED); - finish(); - } - }); + private Button restore; + private Button cancel; + private String path; + + private static final int REQUEST_RESTORE = 0; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.restore_first_time); + path = Preferences.getBackupPath(this); + restore = (Button) findViewById(R.id.restore); + cancel = (Button) findViewById(R.id.cancel); + + ((TextView) findViewById(R.id.filename)).setText(path); + restore.setOnClickListener( + new OnClickListener() { + public void onClick(View v) { + Intent i = new Intent(RestoreFirstTime.this, Restore.class); + i.putExtra(Restore.KEY_FILE_PATH, path); + i.putExtra(Restore.KEY_FIRST_TIME, true); + startActivityForResult(i, REQUEST_RESTORE); + } + } + ); + cancel.setOnClickListener( + new OnClickListener() { + public void onClick(View v) { + setResult(RESULT_CANCELED); + finish(); + } + } + ); /* Copied from AskPassword.java - normalInit() */ - TextView header = (TextView) findViewById(R.id.entry_header); - String version = VersionUtils.getVersionNumber(this); - String appName = VersionUtils.getApplicationName(this); - String head = appName + " " + version; - header.setText(head); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent i) { - super.onActivityResult(requestCode, resultCode, i); - switch (requestCode) { - case REQUEST_RESTORE: - setResult(resultCode); - finish(); - break; - } - } -} \ No newline at end of file + TextView header = (TextView) findViewById(R.id.entry_header); + String version = VersionUtils.getVersionNumber(this); + String appName = VersionUtils.getApplicationName(this); + String head = appName + " " + version; + header.setText(head); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + switch (requestCode) { + case REQUEST_RESTORE: + setResult(resultCode); + finish(); + break; + } + } +} diff --git a/Safe/src/org/openintents/safe/RestoreHandler.java b/Safe/src/org/openintents/safe/RestoreHandler.java index 68f84f91..c02cf242 100644 --- a/Safe/src/org/openintents/safe/RestoreHandler.java +++ b/Safe/src/org/openintents/safe/RestoreHandler.java @@ -16,189 +16,204 @@ */ package org.openintents.safe; +import android.util.Log; + import org.xml.sax.Attributes; import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import android.util.Log; +import org.xml.sax.helpers.DefaultHandler; public class RestoreHandler extends DefaultHandler { - private static boolean debug = false; - private static final String TAG = "Restore"; - - // =========================================================== - // Fields - // =========================================================== - - private boolean in_oisafe = false; - private boolean in_salt = false; - private boolean in_masterkey = false; - private boolean in_category = false; - private boolean in_entry = false; - private boolean in_rowid = false; - private boolean in_description = false; - private boolean in_website = false; - private boolean in_username = false; - private boolean in_password = false; - private boolean in_note = false; - private boolean in_uniquename = false; - private boolean in_packageaccess = false; - - private RestoreDataSet myRestoreDataSet = new RestoreDataSet(); - - // =========================================================== - // Getter & Setter - // =========================================================== - - public RestoreDataSet getParsedData() { - return this.myRestoreDataSet; - } - - // =========================================================== - // Methods - // =========================================================== - @Override - public void startDocument() throws SAXException { - this.myRestoreDataSet = new RestoreDataSet(); - } - - @Override - public void endDocument() throws SAXException { - // Nothing to do - } - - /** Called on opening tags like: - * <tag> - * - * Can provide attribute(s) from xml like: - * <tag attribute="attributeValue">*/ - @Override - public void startElement(String namespaceURI, String localName, - String qName, Attributes atts) throws SAXException { - - if (localName.equals("OISafe")) { - in_oisafe = true; - String attrValue = atts.getValue("version"); - int version = Integer.parseInt(attrValue); - - String date = atts.getValue("date"); - - myRestoreDataSet.setVersion(version); - myRestoreDataSet.setDate(date); - - if (debug) Log.d(TAG,"found OISafe "+version+" date "+date); - - }else if (in_oisafe && localName.equals("Salt")) { - in_salt = true; - - if (debug) Log.d(TAG,"found Salt"); - - }else if (in_oisafe && localName.equals("MasterKey")) { - in_masterkey = true; - - if (debug) Log.d(TAG,"found MasterKey"); - - }else if (in_oisafe && localName.equals("Category")) { - in_category = true; - - String name = atts.getValue("name"); - myRestoreDataSet.newCategory(name); - - if (debug) Log.d(TAG,"found Category "+name); - - }else if (in_category && localName.equals("Entry")) { - this.in_entry = true; - - myRestoreDataSet.newEntry(); - - if (debug) Log.d(TAG,"found Entry"); - - }else if (in_entry && localName.equals("RowID")) { - in_rowid = true; - }else if (in_entry && localName.equals("Description")) { - in_description = true; - }else if (in_entry && localName.equals("Website")) { - in_website = true; - }else if (in_entry && localName.equals("Username")) { - in_username = true; - }else if (in_entry && localName.equals("Password")) { - in_password = true; - }else if (in_entry && localName.equals("Note")) { - in_note = true; - }else if (in_entry && localName.equals("UniqueName")) { - in_uniquename = true; - }else if (in_entry && localName.equals("PackageAccess")) { - in_packageaccess = true; - } - } - - /** Called on closing tags like: - * </tag> - */ - @Override - public void endElement(String namespaceURI, String localName, String qName) - throws SAXException { - - if (localName.equals("OISafe")) { - in_oisafe = false; - }else if (in_oisafe && localName.equals("Salt")) { - in_salt = false; - }else if (in_oisafe && localName.equals("MasterKey")) { - in_masterkey = false; - }else if (in_oisafe && localName.equals("Category")) { - in_category = false; - - myRestoreDataSet.storyCategory(); - - }else if (in_category && localName.equals("Entry")) { - in_entry = false; - - myRestoreDataSet.storeEntry(); - - }else if (in_entry && localName.equals("RowID")) { - in_rowid = false; - }else if (in_entry && localName.equals("Description")) { - in_description = false; - }else if (in_entry && localName.equals("Website")) { - in_website = false; - }else if (in_entry && localName.equals("Username")) { - in_username = false; - }else if (in_entry && localName.equals("Password")) { - in_password = false; - }else if (in_entry && localName.equals("Note")) { - in_note = false; - }else if (in_entry && localName.equals("UniqueName")) { - in_uniquename = false; - }else if (in_entry && localName.equals("PackageAccess")) { - in_packageaccess = false; - } - } - - /** Called on the following structure: - * <tag>characters</tag> */ - @Override - public void characters(char ch[], int start, int length) { - if (in_salt){ - myRestoreDataSet.setSalt(new String(ch, start, length)); - } else if (in_masterkey){ - myRestoreDataSet.setMasterKeyEncrypted(new String(ch, start, length)); - } else if (in_rowid){ - myRestoreDataSet.setRowID(new String(ch, start, length)); - } else if (in_description){ - myRestoreDataSet.setDescription(new String(ch, start, length)); - } else if (in_website){ - myRestoreDataSet.setWebsite(new String(ch, start, length)); - } else if (in_username){ - myRestoreDataSet.setUsername(new String(ch, start, length)); - } else if (in_password){ - myRestoreDataSet.setPassword(new String(ch, start, length)); - } else if (in_note){ - myRestoreDataSet.setNote(new String(ch, start, length)); - } else if (in_uniquename){ - myRestoreDataSet.setUniqueName(new String(ch, start, length)); - } else if (in_packageaccess){ - myRestoreDataSet.setPackageAccess(new String(ch, start, length)); - } - } + private static boolean debug = false; + private static final String TAG = "Restore"; + + // =========================================================== + // Fields + // =========================================================== + + private boolean in_oisafe = false; + private boolean in_salt = false; + private boolean in_masterkey = false; + private boolean in_category = false; + private boolean in_entry = false; + private boolean in_rowid = false; + private boolean in_description = false; + private boolean in_website = false; + private boolean in_username = false; + private boolean in_password = false; + private boolean in_note = false; + private boolean in_uniquename = false; + private boolean in_packageaccess = false; + + private RestoreDataSet myRestoreDataSet = new RestoreDataSet(); + + // =========================================================== + // Getter & Setter + // =========================================================== + + public RestoreDataSet getParsedData() { + return this.myRestoreDataSet; + } + + // =========================================================== + // Methods + // =========================================================== + @Override + public void startDocument() throws SAXException { + this.myRestoreDataSet = new RestoreDataSet(); + } + + @Override + public void endDocument() throws SAXException { + // Nothing to do + } + + /** + * Called on opening tags like: + * <tag> + *

+ * Can provide attribute(s) from xml like: + * <tag attribute="attributeValue"> + */ + @Override + public void startElement(String namespaceURI, String localName, + String qName, Attributes atts) throws SAXException { + + if (localName.equals("OISafe")) { + in_oisafe = true; + String attrValue = atts.getValue("version"); + int version = Integer.parseInt(attrValue); + + String date = atts.getValue("date"); + + myRestoreDataSet.setVersion(version); + myRestoreDataSet.setDate(date); + + if (debug) { + Log.d(TAG, "found OISafe " + version + " date " + date); + } + + } else if (in_oisafe && localName.equals("Salt")) { + in_salt = true; + + if (debug) { + Log.d(TAG, "found Salt"); + } + + } else if (in_oisafe && localName.equals("MasterKey")) { + in_masterkey = true; + + if (debug) { + Log.d(TAG, "found MasterKey"); + } + + } else if (in_oisafe && localName.equals("Category")) { + in_category = true; + + String name = atts.getValue("name"); + myRestoreDataSet.newCategory(name); + + if (debug) { + Log.d(TAG, "found Category " + name); + } + + } else if (in_category && localName.equals("Entry")) { + this.in_entry = true; + + myRestoreDataSet.newEntry(); + + if (debug) { + Log.d(TAG, "found Entry"); + } + + } else if (in_entry && localName.equals("RowID")) { + in_rowid = true; + } else if (in_entry && localName.equals("Description")) { + in_description = true; + } else if (in_entry && localName.equals("Website")) { + in_website = true; + } else if (in_entry && localName.equals("Username")) { + in_username = true; + } else if (in_entry && localName.equals("Password")) { + in_password = true; + } else if (in_entry && localName.equals("Note")) { + in_note = true; + } else if (in_entry && localName.equals("UniqueName")) { + in_uniquename = true; + } else if (in_entry && localName.equals("PackageAccess")) { + in_packageaccess = true; + } + } + + /** + * Called on closing tags like: + * </tag> + */ + @Override + public void endElement(String namespaceURI, String localName, String qName) + throws SAXException { + + if (localName.equals("OISafe")) { + in_oisafe = false; + } else if (in_oisafe && localName.equals("Salt")) { + in_salt = false; + } else if (in_oisafe && localName.equals("MasterKey")) { + in_masterkey = false; + } else if (in_oisafe && localName.equals("Category")) { + in_category = false; + + myRestoreDataSet.storyCategory(); + + } else if (in_category && localName.equals("Entry")) { + in_entry = false; + + myRestoreDataSet.storeEntry(); + + } else if (in_entry && localName.equals("RowID")) { + in_rowid = false; + } else if (in_entry && localName.equals("Description")) { + in_description = false; + } else if (in_entry && localName.equals("Website")) { + in_website = false; + } else if (in_entry && localName.equals("Username")) { + in_username = false; + } else if (in_entry && localName.equals("Password")) { + in_password = false; + } else if (in_entry && localName.equals("Note")) { + in_note = false; + } else if (in_entry && localName.equals("UniqueName")) { + in_uniquename = false; + } else if (in_entry && localName.equals("PackageAccess")) { + in_packageaccess = false; + } + } + + /** + * Called on the following structure: + * <tag>characters</tag> + */ + @Override + public void characters(char ch[], int start, int length) { + if (in_salt) { + myRestoreDataSet.setSalt(new String(ch, start, length)); + } else if (in_masterkey) { + myRestoreDataSet.setMasterKeyEncrypted(new String(ch, start, length)); + } else if (in_rowid) { + myRestoreDataSet.setRowID(new String(ch, start, length)); + } else if (in_description) { + myRestoreDataSet.setDescription(new String(ch, start, length)); + } else if (in_website) { + myRestoreDataSet.setWebsite(new String(ch, start, length)); + } else if (in_username) { + myRestoreDataSet.setUsername(new String(ch, start, length)); + } else if (in_password) { + myRestoreDataSet.setPassword(new String(ch, start, length)); + } else if (in_note) { + myRestoreDataSet.setNote(new String(ch, start, length)); + } else if (in_uniquename) { + myRestoreDataSet.setUniqueName(new String(ch, start, length)); + } else if (in_packageaccess) { + myRestoreDataSet.setPackageAccess(new String(ch, start, length)); + } + } } diff --git a/Safe/src/org/openintents/safe/Safe.java b/Safe/src/org/openintents/safe/Safe.java index b85dd443..9d932b58 100644 --- a/Safe/src/org/openintents/safe/Safe.java +++ b/Safe/src/org/openintents/safe/Safe.java @@ -16,50 +16,57 @@ */ package org.openintents.safe; -import org.openintents.intents.CryptoIntents; - import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; +import org.openintents.intents.CryptoIntents; /** * Safe Activity - * + *

* This activity just makes sure we're entering the front door, not calling encrypt/decrypt * or other intents. - * + * * @author Steven Osborn - http://steven.bitsetters.com */ public class Safe extends Activity { - private static final String TAG = "FrontDoor"; - private static final boolean debug = false; - public static String last_used_password = null; - + private static final String TAG = "FrontDoor"; + private static final boolean debug = false; + public static String last_used_password = null; + // public static final String KEY_AUTOLOCK = "autolock"; - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - if (debug) Log.d(TAG,"onCreate()"); - final Intent thisIntent = getIntent(); - final String action = thisIntent.getAction(); - if (action == null || action.equals(Intent.ACTION_MAIN) || action.equals(CryptoIntents.ACTION_AUTOLOCK)){ - //TODO: When launched from debugger, action is null. Other such cases? - Intent i = new Intent(getApplicationContext(), - IntentHandler.class); + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + if (debug) { + Log.d(TAG, "onCreate()"); + } + final Intent thisIntent = getIntent(); + final String action = thisIntent.getAction(); + if (action == null || action.equals(Intent.ACTION_MAIN) || action.equals(CryptoIntents.ACTION_AUTOLOCK)) { + //TODO: When launched from debugger, action is null. Other such cases? + Intent i = new Intent( + getApplicationContext(), + IntentHandler.class + ); // boolean autoLock = icicle != null ? icicle.getBoolean(FrontDoor.KEY_AUTOLOCK) : false; - if (debug) Log.d(TAG,"action="+action); + if (debug) { + Log.d(TAG, "action=" + action); + } // if (action.equals(CryptoIntents.ACTION_AUTOLOCK)) { - // i.setAction(CryptoIntents.ACTION_AUTOLOCK); - // } - i.setAction(action); - startActivity(i); - } // otherwise, do not start intents, those must be protected by permissions - finish(); - } -} \ No newline at end of file + // i.setAction(CryptoIntents.ACTION_AUTOLOCK); + // } + i.setAction(action); + startActivity(i); + } // otherwise, do not start intents, those must be protected by permissions + finish(); + } +} diff --git a/Safe/src/org/openintents/safe/Search.java b/Safe/src/org/openintents/safe/Search.java index cd86bdf0..ef54053e 100644 --- a/Safe/src/org/openintents/safe/Search.java +++ b/Safe/src/org/openintents/safe/Search.java @@ -15,44 +15,47 @@ */ package org.openintents.safe; -import org.openintents.intents.CryptoIntents; - import android.content.Intent; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.util.Log; +import org.openintents.intents.CryptoIntents; + public class Search extends FragmentActivity { - private final boolean debug = false; - private final String TAG = "Search"; + private final boolean debug = false; + private final String TAG = "Search"; - private Intent restartTimerIntent = null; + private Intent restartTimerIntent = null; - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - if (debug) - Log.d(TAG, "onCreate()"); - setContentView(R.layout.search); + if (debug) { + Log.d(TAG, "onCreate()"); + } + setContentView(R.layout.search); - restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); - } + } - @Override - public void onUserInteraction() { - super.onUserInteraction(); + @Override + public void onUserInteraction() { + super.onUserInteraction(); - if (debug) - Log.d(TAG, "onUserInteraction()"); + if (debug) { + Log.d(TAG, "onUserInteraction()"); + } - if (CategoryList.isSignedIn() == false) { - // startActivity(frontdoor); - } else { - if (restartTimerIntent != null) - sendBroadcast(restartTimerIntent); - } - } + if (CategoryList.isSignedIn() == false) { + // startActivity(frontdoor); + } else { + if (restartTimerIntent != null) { + sendBroadcast(restartTimerIntent); + } + } + } } diff --git a/Safe/src/org/openintents/safe/SearchEntry.java b/Safe/src/org/openintents/safe/SearchEntry.java index b8fef1b4..da04c320 100644 --- a/Safe/src/org/openintents/safe/SearchEntry.java +++ b/Safe/src/org/openintents/safe/SearchEntry.java @@ -22,66 +22,70 @@ * @author Randy McEoin */ public class SearchEntry extends Object implements Parcelable { - public long id = -1; - public String name; - public String category; - public long categoryId = -1; + public long id = -1; + public String name; + public String category; + public long categoryId = -1; - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getCategory() { - return category; - } + public String getCategory() { + return category; + } - public SearchEntry() { - name = ""; - category = ""; - } + public SearchEntry() { + name = ""; + category = ""; + } - public SearchEntry(String _name) { - name = _name; - category = ""; - } + public SearchEntry(String _name) { + name = _name; + category = ""; + } - public SearchEntry(String _name, String _category) { - name = _name; - category = _category; - } + public SearchEntry(String _name, String _category) { + name = _name; + category = _category; + } - @Override - public String toString() { - return name + " " + category; - } + @Override + public String toString() { + return name + " " + category; + } - public int describeContents() { - return 0; - } + public int describeContents() { + return 0; + } - /** save object in parcel */ - public void writeToParcel(Parcel out, int flags) { - out.writeLong(id); - out.writeString(name); - out.writeString(category); - out.writeLong(categoryId); - } + /** + * save object in parcel + */ + public void writeToParcel(Parcel out, int flags) { + out.writeLong(id); + out.writeString(name); + out.writeString(category); + out.writeLong(categoryId); + } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SearchEntry createFromParcel(Parcel in) { - return new SearchEntry(in); - } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public SearchEntry createFromParcel(Parcel in) { + return new SearchEntry(in); + } - public SearchEntry[] newArray(int size) { - return new SearchEntry[size]; - } - }; + public SearchEntry[] newArray(int size) { + return new SearchEntry[size]; + } + }; - /** recreate object from parcel */ - private SearchEntry(Parcel in) { - id = in.readLong(); - name = in.readString(); - category = in.readString(); - categoryId = in.readLong(); - } + /** + * recreate object from parcel + */ + private SearchEntry(Parcel in) { + id = in.readLong(); + name = in.readString(); + category = in.readString(); + categoryId = in.readLong(); + } } diff --git a/Safe/src/org/openintents/safe/SearchFragment.java b/Safe/src/org/openintents/safe/SearchFragment.java index cbd057d7..476e60ef 100644 --- a/Safe/src/org/openintents/safe/SearchFragment.java +++ b/Safe/src/org/openintents/safe/SearchFragment.java @@ -15,14 +15,6 @@ */ package org.openintents.safe; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; - -import org.openintents.intents.CryptoIntents; - import android.app.Activity; import android.app.ProgressDialog; import android.content.BroadcastReceiver; @@ -46,332 +38,379 @@ import android.widget.TextView; import android.widget.Toast; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.openintents.intents.CryptoIntents; + public class SearchFragment extends ListFragment { - private static final String TAG = "Search"; - private static final boolean debug = false; - - public static final int REQUEST_VIEW_PASSWORD = 1; - - public static final String KEY_RESULTS = "results"; - - // Need handler for callbacks to the UI thread - final Handler mHandler = new Handler(); - - // Create runnable for posting - final Runnable mUpdateResults = new Runnable() { - public void run() { - updateResultsInUi(); - } - }; - private Thread searchThread = null; - - private ProgressDialog progressDialog = null; - - private EditText etSearchCriteria; - private String searchCriteria = ""; - private List results = null; - private SearchListItemAdapter searchAdapter = null; - - Intent frontdoor; - private Intent restartTimerIntent = null; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals( - CryptoIntents.ACTION_CRYPTO_LOGGED_OUT)) { - if (debug) - Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); - startActivity(frontdoor); - } - } - }; - - private void updateResultsInUi() { - // Back in the UI thread -- update our UI elements based on the data in - // mResults - searchAdapter = new SearchListItemAdapter(getActivity(), - R.layout.search_row, results); - setListAdapter(searchAdapter); - if ((searchAdapter != null) && (searchAdapter.isEmpty())) { - Toast.makeText(getActivity(), R.string.search_nothing_found, - Toast.LENGTH_LONG).show(); - } - - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - ViewGroup root = (ViewGroup) inflater.inflate(R.layout.search_fragment, - null); - - frontdoor = new Intent(getActivity(), Safe.class); - frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); - restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); - - etSearchCriteria = (EditText) root.findViewById(R.id.search_criteria); - results = new ArrayList(); - - Button goButton = (Button) root.findViewById(R.id.go_button); - goButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - searchCriteria = etSearchCriteria.getText().toString().trim() - .toLowerCase(); - searchThreadStart(); - } - }); - - etSearchCriteria - .setOnEditorActionListener(new TextView.OnEditorActionListener() { - public boolean onEditorAction(TextView v, int actionId, - KeyEvent event) { - // Sadly with Jelly Bean actionId can equal 0 instead of IME_ACTION_SEARCH, - // so the hack event==null is used - if (actionId == EditorInfo.IME_ACTION_SEARCH - || event == null) { - // hide the soft keyboard - InputMethodManager imm = (InputMethodManager) getActivity() - .getSystemService( - Context.INPUT_METHOD_SERVICE); - imm.toggleSoftInput(0, 0); - searchCriteria = etSearchCriteria.getText() - .toString().trim().toLowerCase(); - searchThreadStart(); - return true; - } - return false; - } - }); - - return root; - } - - @Override - public void onPause() { - super.onPause(); - - if (debug) - Log.d(TAG, "onPause()"); - - if ((searchThread != null) && (searchThread.isAlive())) { - if (debug) - Log.d(TAG, "wait for search thread"); - int maxWaitToDie = 500000; - try { - searchThread.join(maxWaitToDie); - } catch (InterruptedException e) { - } // ignore - } - try { - getActivity().unregisterReceiver(mIntentReceiver); - } catch (IllegalArgumentException e) { - // if (debug) Log.d(TAG,"IllegalArgumentException"); - } - } - - @Override - public void onResume() { - super.onResume(); - - if (debug) - Log.d(TAG, "onResume()"); - - if (CategoryList.isSignedIn() == false) { - startActivity(frontdoor); - return; - } - IntentFilter filter = new IntentFilter( - CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - getActivity().registerReceiver(mIntentReceiver, filter); - - Passwords.Initialize(getActivity()); - } - - public static long[] getRowsIds(List rows) { - if (debug) - Log.d(TAG, "getRowsIds() rows=" + rows); - if (rows != null) { - long[] ids = new long[rows.size()]; - Iterator searchIter = rows.iterator(); - int i = 0; - while (searchIter.hasNext()) { - ids[i] = searchIter.next().id; - i++; - } - return ids; - } else { - return null; - } - } - - public void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - - if (debug) - Log.d(TAG, "onListItemClick: position=" + position + " results=" - + results); - if ((results == null) || (results.size() == 0)) { - return; - } - Intent passView = new Intent(getActivity(), PassView.class); - passView.putExtra(PassList.KEY_ID, results.get(position).id); - if (debug) - Log.d(TAG, "onListItemClick: category=" - + results.get(position).category); - passView.putExtra(PassList.KEY_CATEGORY_ID, - results.get(position).categoryId); - passView.putExtra(PassList.KEY_ROWIDS, getRowsIds(results)); - passView.putExtra(PassList.KEY_LIST_POSITION, position); - startActivityForResult(passView, REQUEST_VIEW_PASSWORD); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent i) { - super.onActivityResult(requestCode, resultCode, i); - - if (((requestCode == REQUEST_VIEW_PASSWORD) && (PassView.entryEdited)) - || (resultCode == Activity.RESULT_OK)) { - searchCriteria = etSearchCriteria.getText().toString().trim() - .toLowerCase(); - searchThreadStart(); - } - } - - /** - * Start a separate thread to search the database. By running the search in - * a thread it allows the main UI thread to return and permit the updating - * of the progress dialog. - */ - private void searchThreadStart() { - if (searchThread != null) { - if (searchThread.isAlive()) { - // it's already searching - } else { - // just rerun - progressDialog.show(); - searchThread.run(); - } - return; - } - - progressDialog = new ProgressDialog(getActivity()); - progressDialog.setMessage(getString(R.string.search_progress)); - progressDialog.setIndeterminate(false); - progressDialog.setCancelable(true); - progressDialog.show(); - - searchThread = new Thread(new Runnable() { - public void run() { - doSearch(); - progressDialog.dismiss(); - getActivity().sendBroadcast(restartTimerIntent); - - mHandler.post(mUpdateResults); - - if (debug) - Log.d(TAG, "thread end"); - } - }, "Search"); - searchThread.start(); - } - - private void doSearch() { - if (debug) - Log.d(TAG, "doSearch: searchCriteria=" + searchCriteria); - results.clear(); - if (searchCriteria.length() == 0) { - // don't bother searching for nothing - return; - } - - List categories = Passwords.getCategoryEntries(); - for (CategoryEntry catRow : categories) { - if (debug) - Log.d(TAG, "doSearch: category=" + catRow.plainName); - List passwords = Passwords.getPassEntries(catRow.id, - true, false); - for (PassEntry passRow : passwords) { - if (searchThread.isInterrupted()) { - return; - } - - String description = passRow.plainDescription.toLowerCase(); - String website = passRow.plainWebsite.toLowerCase(); - String username = passRow.plainUsername.toLowerCase(); - String password = passRow.plainPassword.toLowerCase(); - String note = passRow.plainNote.toLowerCase(); - if (description.contains(searchCriteria) - || website.contains(searchCriteria) - || username.contains(searchCriteria) - || password.contains(searchCriteria) - || note.contains(searchCriteria)) { - if (debug) - Log.d(TAG, "matches: " + passRow.plainDescription); - SearchEntry searchRow = new SearchEntry(); - searchRow.name = passRow.plainDescription; - searchRow.id = passRow.id; - searchRow.category = catRow.plainName; - searchRow.categoryId = catRow.id; - results.add(searchRow); - continue; - } - } - } - - Collections.sort(results, new Comparator() { - public int compare(SearchEntry o1, SearchEntry o2) { - return o1.name.compareToIgnoreCase(o2.name); - } - }); - - updateListFromResults(); - } - - private void updateListFromResults() { - if (results == null) { - return; - } - searchAdapter = new SearchListItemAdapter(getActivity(), - R.layout.search_row, results); - } - - /** - * If we have results, save them for use with onActivityCreated() - */ - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (results != null) { - SearchEntry[] aResults = new SearchEntry[results.size()]; - results.toArray(aResults); - outState.putParcelableArray(KEY_RESULTS, aResults); - } - } - - /** - * Restore results from onSaveInstanceState() - */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - if (debug) - Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")"); - - if ((savedInstanceState != null) - && (savedInstanceState.containsKey(KEY_RESULTS)) - && (results != null)) { - Parcelable[] parcels = savedInstanceState - .getParcelableArray(KEY_RESULTS); - for (Parcelable par : parcels) { - results.add((SearchEntry) par); - } - if (results.size() > 0) { - updateResultsInUi(); - } - } - } + private static final String TAG = "Search"; + private static final boolean debug = false; + + public static final int REQUEST_VIEW_PASSWORD = 1; + + public static final String KEY_RESULTS = "results"; + + // Need handler for callbacks to the UI thread + final Handler mHandler = new Handler(); + + // Create runnable for posting + final Runnable mUpdateResults = new Runnable() { + public void run() { + updateResultsInUi(); + } + }; + private Thread searchThread = null; + + private ProgressDialog progressDialog = null; + + private EditText etSearchCriteria; + private String searchCriteria = ""; + private List results = null; + private SearchListItemAdapter searchAdapter = null; + + Intent frontdoor; + private Intent restartTimerIntent = null; + + BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals( + CryptoIntents.ACTION_CRYPTO_LOGGED_OUT + )) { + if (debug) { + Log.d(TAG, "caught ACTION_CRYPTO_LOGGED_OUT"); + } + startActivity(frontdoor); + } + } + }; + + private void updateResultsInUi() { + // Back in the UI thread -- update our UI elements based on the data in + // mResults + searchAdapter = new SearchListItemAdapter( + getActivity(), + R.layout.search_row, results + ); + setListAdapter(searchAdapter); + if ((searchAdapter != null) && (searchAdapter.isEmpty())) { + Toast.makeText( + getActivity(), R.string.search_nothing_found, + Toast.LENGTH_LONG + ).show(); + } + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + ViewGroup root = (ViewGroup) inflater.inflate( + R.layout.search_fragment, + null + ); + + frontdoor = new Intent(getActivity(), Safe.class); + frontdoor.setAction(CryptoIntents.ACTION_AUTOLOCK); + restartTimerIntent = new Intent(CryptoIntents.ACTION_RESTART_TIMER); + + etSearchCriteria = (EditText) root.findViewById(R.id.search_criteria); + results = new ArrayList(); + + Button goButton = (Button) root.findViewById(R.id.go_button); + goButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + searchCriteria = etSearchCriteria.getText().toString().trim() + .toLowerCase(); + searchThreadStart(); + } + } + ); + + etSearchCriteria + .setOnEditorActionListener( + new TextView.OnEditorActionListener() { + public boolean onEditorAction(TextView v, int actionId, + KeyEvent event) { + // Sadly with Jelly Bean actionId can equal 0 instead of IME_ACTION_SEARCH, + // so the hack event==null is used + if (actionId == EditorInfo.IME_ACTION_SEARCH + || event == null) { + // hide the soft keyboard + InputMethodManager imm = (InputMethodManager) getActivity() + .getSystemService( + Context.INPUT_METHOD_SERVICE + ); + imm.toggleSoftInput(0, 0); + searchCriteria = etSearchCriteria.getText() + .toString().trim().toLowerCase(); + searchThreadStart(); + return true; + } + return false; + } + } + ); + + return root; + } + + @Override + public void onPause() { + super.onPause(); + + if (debug) { + Log.d(TAG, "onPause()"); + } + + if ((searchThread != null) && (searchThread.isAlive())) { + if (debug) { + Log.d(TAG, "wait for search thread"); + } + int maxWaitToDie = 500000; + try { + searchThread.join(maxWaitToDie); + } catch (InterruptedException e) { + } // ignore + } + try { + getActivity().unregisterReceiver(mIntentReceiver); + } catch (IllegalArgumentException e) { + // if (debug) Log.d(TAG,"IllegalArgumentException"); + } + } + + @Override + public void onResume() { + super.onResume(); + + if (debug) { + Log.d(TAG, "onResume()"); + } + + if (CategoryList.isSignedIn() == false) { + startActivity(frontdoor); + return; + } + IntentFilter filter = new IntentFilter( + CryptoIntents.ACTION_CRYPTO_LOGGED_OUT + ); + getActivity().registerReceiver(mIntentReceiver, filter); + + Passwords.Initialize(getActivity()); + } + + public static long[] getRowsIds(List rows) { + if (debug) { + Log.d(TAG, "getRowsIds() rows=" + rows); + } + if (rows != null) { + long[] ids = new long[rows.size()]; + Iterator searchIter = rows.iterator(); + int i = 0; + while (searchIter.hasNext()) { + ids[i] = searchIter.next().id; + i++; + } + return ids; + } else { + return null; + } + } + + public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + + if (debug) { + Log.d( + TAG, "onListItemClick: position=" + position + " results=" + + results + ); + } + if ((results == null) || (results.size() == 0)) { + return; + } + Intent passView = new Intent(getActivity(), PassView.class); + passView.putExtra(PassList.KEY_ID, results.get(position).id); + if (debug) { + Log.d( + TAG, "onListItemClick: category=" + + results.get(position).category + ); + } + passView.putExtra( + PassList.KEY_CATEGORY_ID, + results.get(position).categoryId + ); + passView.putExtra(PassList.KEY_ROWIDS, getRowsIds(results)); + passView.putExtra(PassList.KEY_LIST_POSITION, position); + startActivityForResult(passView, REQUEST_VIEW_PASSWORD); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent i) { + super.onActivityResult(requestCode, resultCode, i); + + if (((requestCode == REQUEST_VIEW_PASSWORD) && (PassView.entryEdited)) + || (resultCode == Activity.RESULT_OK)) { + searchCriteria = etSearchCriteria.getText().toString().trim() + .toLowerCase(); + searchThreadStart(); + } + } + + /** + * Start a separate thread to search the database. By running the search in + * a thread it allows the main UI thread to return and permit the updating + * of the progress dialog. + */ + private void searchThreadStart() { + if (searchThread != null) { + if (searchThread.isAlive()) { + // it's already searching + } else { + // just rerun + progressDialog.show(); + searchThread.run(); + } + return; + } + + progressDialog = new ProgressDialog(getActivity()); + progressDialog.setMessage(getString(R.string.search_progress)); + progressDialog.setIndeterminate(false); + progressDialog.setCancelable(true); + progressDialog.show(); + + searchThread = new Thread( + new Runnable() { + public void run() { + doSearch(); + progressDialog.dismiss(); + getActivity().sendBroadcast(restartTimerIntent); + + mHandler.post(mUpdateResults); + + if (debug) { + Log.d(TAG, "thread end"); + } + } + }, "Search" + ); + searchThread.start(); + } + + private void doSearch() { + if (debug) { + Log.d(TAG, "doSearch: searchCriteria=" + searchCriteria); + } + results.clear(); + if (searchCriteria.length() == 0) { + // don't bother searching for nothing + return; + } + + List categories = Passwords.getCategoryEntries(); + for (CategoryEntry catRow : categories) { + if (debug) { + Log.d(TAG, "doSearch: category=" + catRow.plainName); + } + List passwords = Passwords.getPassEntries( + catRow.id, + true, false + ); + for (PassEntry passRow : passwords) { + if (searchThread.isInterrupted()) { + return; + } + + String description = passRow.plainDescription.toLowerCase(); + String website = passRow.plainWebsite.toLowerCase(); + String username = passRow.plainUsername.toLowerCase(); + String password = passRow.plainPassword.toLowerCase(); + String note = passRow.plainNote.toLowerCase(); + if (description.contains(searchCriteria) + || website.contains(searchCriteria) + || username.contains(searchCriteria) + || password.contains(searchCriteria) + || note.contains(searchCriteria)) { + if (debug) { + Log.d(TAG, "matches: " + passRow.plainDescription); + } + SearchEntry searchRow = new SearchEntry(); + searchRow.name = passRow.plainDescription; + searchRow.id = passRow.id; + searchRow.category = catRow.plainName; + searchRow.categoryId = catRow.id; + results.add(searchRow); + continue; + } + } + } + + Collections.sort( + results, new Comparator() { + public int compare(SearchEntry o1, SearchEntry o2) { + return o1.name.compareToIgnoreCase(o2.name); + } + } + ); + + updateListFromResults(); + } + + private void updateListFromResults() { + if (results == null) { + return; + } + searchAdapter = new SearchListItemAdapter( + getActivity(), + R.layout.search_row, results + ); + } + + /** + * If we have results, save them for use with onActivityCreated() + */ + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (results != null) { + SearchEntry[] aResults = new SearchEntry[results.size()]; + results.toArray(aResults); + outState.putParcelableArray(KEY_RESULTS, aResults); + } + } + + /** + * Restore results from onSaveInstanceState() + */ + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + if (debug) { + Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")"); + } + + if ((savedInstanceState != null) + && (savedInstanceState.containsKey(KEY_RESULTS)) + && (results != null)) { + Parcelable[] parcels = savedInstanceState + .getParcelableArray(KEY_RESULTS); + for (Parcelable par : parcels) { + results.add((SearchEntry) par); + } + if (results.size() > 0) { + updateResultsInUi(); + } + } + } } diff --git a/Safe/src/org/openintents/safe/SearchListItemAdapter.java b/Safe/src/org/openintents/safe/SearchListItemAdapter.java index 6dfea6b5..61a3d929 100644 --- a/Safe/src/org/openintents/safe/SearchListItemAdapter.java +++ b/Safe/src/org/openintents/safe/SearchListItemAdapter.java @@ -16,8 +16,6 @@ */ package org.openintents.safe; -import java.util.List; - import android.content.Context; import android.util.Log; import android.view.LayoutInflater; @@ -27,52 +25,56 @@ import android.widget.LinearLayout; import android.widget.TextView; +import java.util.List; + /** * @author Randy McEoin - * - * Many thanks to Professional Android Application Development by Reto Meier - * from which this adapter is based upon. + *

+ * Many thanks to Professional Android Application Development by Reto Meier + * from which this adapter is based upon. */ public class SearchListItemAdapter extends ArrayAdapter { - private static boolean debug = false; - private static final String TAG = "SearchListItemAdapter"; - - int resource; - - public SearchListItemAdapter(Context _context, int _resource, - List _items) { - super(_context, _resource, _items); - resource = _resource; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - LinearLayout searchListView; - - SearchEntry item = getItem(position); - - String name = item.name; - String category = item.category; - - if (convertView == null) { - searchListView = new LinearLayout(getContext()); - String inflater = Context.LAYOUT_INFLATER_SERVICE; - LayoutInflater vi; - vi = (LayoutInflater)getContext().getSystemService(inflater); - vi.inflate(resource, searchListView, true); - } else { - searchListView = (LinearLayout) convertView; - } - - TextView nameView = (TextView)searchListView.findViewById(R.id.rowName); - TextView categoryView = (TextView)searchListView.findViewById(R.id.rowCategory); - - if (debug) Log.d(TAG, "category="+category); - nameView.setText(name); - categoryView.setText(category); - - return searchListView; - } + private static boolean debug = false; + private static final String TAG = "SearchListItemAdapter"; + + int resource; + + public SearchListItemAdapter(Context _context, int _resource, + List _items) { + super(_context, _resource, _items); + resource = _resource; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + LinearLayout searchListView; + + SearchEntry item = getItem(position); + + String name = item.name; + String category = item.category; + + if (convertView == null) { + searchListView = new LinearLayout(getContext()); + String inflater = Context.LAYOUT_INFLATER_SERVICE; + LayoutInflater vi; + vi = (LayoutInflater) getContext().getSystemService(inflater); + vi.inflate(resource, searchListView, true); + } else { + searchListView = (LinearLayout) convertView; + } + + TextView nameView = (TextView) searchListView.findViewById(R.id.rowName); + TextView categoryView = (TextView) searchListView.findViewById(R.id.rowCategory); + + if (debug) { + Log.d(TAG, "category=" + category); + } + nameView.setText(name); + categoryView.setText(category); + + return searchListView; + } } diff --git a/Safe/src/org/openintents/safe/SimpleGestureFilter.java b/Safe/src/org/openintents/safe/SimpleGestureFilter.java index 6beaf47c..0d965fd3 100644 --- a/Safe/src/org/openintents/safe/SimpleGestureFilter.java +++ b/Safe/src/org/openintents/safe/SimpleGestureFilter.java @@ -8,182 +8,192 @@ /** * Simple Guesture Filter - * + *

* Found this code at the following URL. - * + *

* http://android-journey.blogspot.com/2010/01/android-gestures.html - * + * * @author Amir Sadrinia */ -public class SimpleGestureFilter extends SimpleOnGestureListener{ - - private final static boolean debug = false; - private final static String TAG = "SimpleGestureFilter"; - - public final static int SWIPE_UP = 1; - public final static int SWIPE_DOWN = 2; - public final static int SWIPE_LEFT = 3; - public final static int SWIPE_RIGHT = 4; - - public final static int MODE_TRANSPARENT = 0; - public final static int MODE_SOLID = 1; - public final static int MODE_DYNAMIC = 2; - - private final static int ACTION_FAKE = -13; //just an unlikely number - private int swipe_Min_Distance = 60; - private int swipe_Max_Distance = 350; - private int swipe_Min_Velocity = 50; - - private int viewWidth=400; - - private int mode = MODE_DYNAMIC; - private boolean running = true; - private boolean tapIndicator = false; - - private Activity context; - private GestureDetector detector; - private SimpleGestureListener listener; - - public SimpleGestureFilter(Activity context,SimpleGestureListener sgl) { - - this.context = context; - this.detector = new GestureDetector(context, this); - this.listener = sgl; - } - - public void setViewWidth(int width) { - if (width>0) { - viewWidth=width; - swipe_Min_Distance = (int) Math.round(viewWidth * 0.15); - swipe_Max_Distance = (int) Math.round(viewWidth * 0.80); - if (debug) Log.d(TAG,"min="+swipe_Min_Distance+" max="+swipe_Max_Distance); - } - } - public void onTouchEvent(MotionEvent event){ - - if (!this.running) - return; - - boolean result = this.detector.onTouchEvent(event); - - if (this.mode == MODE_SOLID) - event.setAction(MotionEvent.ACTION_CANCEL); - else if (this.mode == MODE_DYNAMIC) { - - if (event.getAction() == ACTION_FAKE) - event.setAction(MotionEvent.ACTION_UP); - else if (result) - event.setAction(MotionEvent.ACTION_CANCEL); - else if (this.tapIndicator){ - event.setAction(MotionEvent.ACTION_DOWN); - this.tapIndicator = false; - } - - } - //else just do nothing, it's Transparent - } - - public void setMode(int m){ - this.mode = m; - } - - public int getMode(){ - return this.mode; - } - - public void setEnabled(boolean status){ - this.running = status; - } - - public void setSwipeMaxDistance(int distance){ - this.swipe_Max_Distance = distance; - } - - public void setSwipeMinDistance(int distance){ - this.swipe_Min_Distance = distance; - } - - public void setSwipeMinVelocity(int distance){ - this.swipe_Min_Velocity = distance; - } - - public int getSwipeMaxDistance(){ - return this.swipe_Max_Distance; - } - - public int getSwipeMinDistance(){ - return this.swipe_Min_Distance; - } - - public int getSwipeMinVelocity(){ - return this.swipe_Min_Velocity; - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, - float velocityY) { - - final float xDistance = Math.abs(e1.getX() - e2.getX()); - final float yDistance = Math.abs(e1.getY() - e2.getY()); - - if (xDistance > this.swipe_Max_Distance || yDistance > this.swipe_Max_Distance) - return false; - - velocityX = Math.abs(velocityX); - velocityY = Math.abs(velocityY); - boolean result = false; - - if (velocityX > this.swipe_Min_Velocity && xDistance > this.swipe_Min_Distance){ - if(e1.getX() > e2.getX()) // right to left - this.listener.onSwipe(SWIPE_LEFT); - else - this.listener.onSwipe(SWIPE_RIGHT); - - result = true; - } - else if (velocityY > this.swipe_Min_Velocity && yDistance > this.swipe_Min_Distance){ - if (e1.getY() > e2.getY()) // bottom to up - this.listener.onSwipe(SWIPE_UP); - else - this.listener.onSwipe(SWIPE_DOWN); - // don't actually use this - result = false; - } - - return result; - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - this.tapIndicator = true; - return false; - } - - @Override - public boolean onDoubleTap(MotionEvent arg0) { - this.listener.onDoubleTap();; - return true; - } - - @Override - public boolean onDoubleTapEvent(MotionEvent arg0) { - return true; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent arg0) { - - if (this.mode == MODE_DYNAMIC){ // we owe an ACTION_UP, so we fake an - arg0.setAction(ACTION_FAKE); //action which will be converted to an ACTION_UP later. - this.context.dispatchTouchEvent(arg0); - } - - return false; - } - - static interface SimpleGestureListener{ - void onSwipe(int direction); - void onDoubleTap(); - } +public class SimpleGestureFilter extends SimpleOnGestureListener { + + private final static boolean debug = false; + private final static String TAG = "SimpleGestureFilter"; + + public final static int SWIPE_UP = 1; + public final static int SWIPE_DOWN = 2; + public final static int SWIPE_LEFT = 3; + public final static int SWIPE_RIGHT = 4; + + public final static int MODE_TRANSPARENT = 0; + public final static int MODE_SOLID = 1; + public final static int MODE_DYNAMIC = 2; + + private final static int ACTION_FAKE = -13; //just an unlikely number + private int swipe_Min_Distance = 60; + private int swipe_Max_Distance = 350; + private int swipe_Min_Velocity = 50; + + private int viewWidth = 400; + + private int mode = MODE_DYNAMIC; + private boolean running = true; + private boolean tapIndicator = false; + + private Activity context; + private GestureDetector detector; + private SimpleGestureListener listener; + + public SimpleGestureFilter(Activity context, SimpleGestureListener sgl) { + + this.context = context; + this.detector = new GestureDetector(context, this); + this.listener = sgl; + } + + public void setViewWidth(int width) { + if (width > 0) { + viewWidth = width; + swipe_Min_Distance = (int) Math.round(viewWidth * 0.15); + swipe_Max_Distance = (int) Math.round(viewWidth * 0.80); + if (debug) { + Log.d(TAG, "min=" + swipe_Min_Distance + " max=" + swipe_Max_Distance); + } + } + } + + public void onTouchEvent(MotionEvent event) { + + if (!this.running) { + return; + } + + boolean result = this.detector.onTouchEvent(event); + + if (this.mode == MODE_SOLID) { + event.setAction(MotionEvent.ACTION_CANCEL); + } else if (this.mode == MODE_DYNAMIC) { + + if (event.getAction() == ACTION_FAKE) { + event.setAction(MotionEvent.ACTION_UP); + } else if (result) { + event.setAction(MotionEvent.ACTION_CANCEL); + } else if (this.tapIndicator) { + event.setAction(MotionEvent.ACTION_DOWN); + this.tapIndicator = false; + } + + } + //else just do nothing, it's Transparent + } + + public void setMode(int m) { + this.mode = m; + } + + public int getMode() { + return this.mode; + } + + public void setEnabled(boolean status) { + this.running = status; + } + + public void setSwipeMaxDistance(int distance) { + this.swipe_Max_Distance = distance; + } + + public void setSwipeMinDistance(int distance) { + this.swipe_Min_Distance = distance; + } + + public void setSwipeMinVelocity(int distance) { + this.swipe_Min_Velocity = distance; + } + + public int getSwipeMaxDistance() { + return this.swipe_Max_Distance; + } + + public int getSwipeMinDistance() { + return this.swipe_Min_Distance; + } + + public int getSwipeMinVelocity() { + return this.swipe_Min_Velocity; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + + final float xDistance = Math.abs(e1.getX() - e2.getX()); + final float yDistance = Math.abs(e1.getY() - e2.getY()); + + if (xDistance > this.swipe_Max_Distance || yDistance > this.swipe_Max_Distance) { + return false; + } + + velocityX = Math.abs(velocityX); + velocityY = Math.abs(velocityY); + boolean result = false; + + if (velocityX > this.swipe_Min_Velocity && xDistance > this.swipe_Min_Distance) { + if (e1.getX() > e2.getX()) // right to left + { + this.listener.onSwipe(SWIPE_LEFT); + } else { + this.listener.onSwipe(SWIPE_RIGHT); + } + + result = true; + } else if (velocityY > this.swipe_Min_Velocity && yDistance > this.swipe_Min_Distance) { + if (e1.getY() > e2.getY()) // bottom to up + { + this.listener.onSwipe(SWIPE_UP); + } else { + this.listener.onSwipe(SWIPE_DOWN); + } + // don't actually use this + result = false; + } + + return result; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + this.tapIndicator = true; + return false; + } + + @Override + public boolean onDoubleTap(MotionEvent arg0) { + this.listener.onDoubleTap(); + ; + return true; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent arg0) { + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent arg0) { + + if (this.mode == MODE_DYNAMIC) { // we owe an ACTION_UP, so we fake an + arg0.setAction(ACTION_FAKE); //action which will be converted to an ACTION_UP later. + this.context.dispatchTouchEvent(arg0); + } + + return false; + } + + static interface SimpleGestureListener { + void onSwipe(int direction); + + void onDoubleTap(); + } } diff --git a/Safe/src/org/openintents/safe/dialog/AllowExternalAccessDialog.java b/Safe/src/org/openintents/safe/dialog/AllowExternalAccessDialog.java index 2ba3518c..1a96deb4 100644 --- a/Safe/src/org/openintents/safe/dialog/AllowExternalAccessDialog.java +++ b/Safe/src/org/openintents/safe/dialog/AllowExternalAccessDialog.java @@ -1,87 +1,83 @@ package org.openintents.safe.dialog; -import org.openintents.safe.Preferences; -import org.openintents.safe.R; - import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import android.content.SharedPreferences; import android.content.DialogInterface.OnClickListener; +import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; +import org.openintents.safe.Preferences; +import org.openintents.safe.R; + /** * This dialog is presented when an external application wants to use OI Safe for * encryption. An example is OI Notepad. When a user tells Notepad to encrypt * a note and OI Safe does not already allow for external access, this dialog will * come up. - * */ public class AllowExternalAccessDialog extends AlertDialog implements OnClickListener { // private static final String TAG = "FilenameDialog"; - private static final String BUNDLE_TAGS = "tags"; - - protected static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 2; - - Context mContext; - - CheckBox mCheckBox; + private static final String BUNDLE_TAGS = "tags"; - public AllowExternalAccessDialog(Context context) { - super(context); - mContext = context; + protected static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 2; - setTitle(context.getText(R.string.dialog_title_external_access)); - setButton(BUTTON_POSITIVE, context.getText(android.R.string.ok), this); - setButton(BUTTON_NEGATIVE, context.getText(android.R.string.cancel), (OnClickListener) null); - setIcon(android.R.drawable.ic_dialog_alert); + Context mContext; - LayoutInflater inflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.dialog_allow_access, null); - setView(view); + CheckBox mCheckBox; + public AllowExternalAccessDialog(Context context) { + super(context); + mContext = context; - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - boolean externalAccess = sp.getBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, false); + setTitle(context.getText(R.string.dialog_title_external_access)); + setButton(BUTTON_POSITIVE, context.getText(android.R.string.ok), this); + setButton(BUTTON_NEGATIVE, context.getText(android.R.string.cancel), (OnClickListener) null); + setIcon(android.R.drawable.ic_dialog_alert); - mCheckBox = (CheckBox) view.findViewById(R.id.checkbox); - // mCheckBox.setText(R.string.pref_summary_external_access); - mCheckBox.setChecked(externalAccess); + LayoutInflater inflater = + (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflater.inflate(R.layout.dialog_allow_access, null); + setView(view); - } + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + boolean externalAccess = sp.getBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, false); + mCheckBox = (CheckBox) view.findViewById(R.id.checkbox); + // mCheckBox.setText(R.string.pref_summary_external_access); + mCheckBox.setChecked(externalAccess); - public void onClick(DialogInterface dialog, int which) { - if (which == BUTTON_POSITIVE) { - // User pressed OK - boolean externalAccess = mCheckBox.isChecked(); + } - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, externalAccess); - editor.commit(); + public void onClick(DialogInterface dialog, int which) { + if (which == BUTTON_POSITIVE) { + // User pressed OK + boolean externalAccess = mCheckBox.isChecked(); - } + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(Preferences.PREFERENCE_ALLOW_EXTERNAL_ACCESS, externalAccess); + editor.commit(); - } + } + } - @Override - public Bundle onSaveInstanceState() { - Bundle state = super.onSaveInstanceState(); - state.putString(BUNDLE_TAGS, ""); - return state; - } + @Override + public Bundle onSaveInstanceState() { + Bundle state = super.onSaveInstanceState(); + state.putString(BUNDLE_TAGS, ""); + return state; + } - @Override - public void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); // String tags = savedInstanceState.getString(BUNDLE_TAGS); - } + } } diff --git a/Safe/src/org/openintents/safe/dialog/DialogHostingActivity.java b/Safe/src/org/openintents/safe/dialog/DialogHostingActivity.java index 336be0dd..2e792024 100644 --- a/Safe/src/org/openintents/safe/dialog/DialogHostingActivity.java +++ b/Safe/src/org/openintents/safe/dialog/DialogHostingActivity.java @@ -1,9 +1,5 @@ package org.openintents.safe.dialog; -import org.openintents.distribution.DownloadOIAppDialog; -import org.openintents.intents.FileManagerIntents; -import org.openintents.util.IntentUtils; - import android.app.Activity; import android.app.Dialog; import android.content.DialogInterface; @@ -13,191 +9,225 @@ import android.util.Log; import android.widget.EditText; +import org.openintents.distribution.DownloadOIAppDialog; +import org.openintents.intents.FileManagerIntents; +import org.openintents.util.IntentUtils; + public class DialogHostingActivity extends Activity { - private static final String TAG = "DialogHostingActivity"; - private static final boolean debug = false; - - public static final int DIALOG_ID_SAVE = 1; - public static final int DIALOG_ID_OPEN = 2; - public static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 3; - public static final int DIALOG_ID_ALLOW_EXTERNAL_ACCESS = 4; - public static final int DIALOG_ID_FIRST_TIME_WARNING = 5; - - public static final String EXTRA_DIALOG_ID = "org.openintents.notepad.extra.dialog_id"; - - /** - * Whether dialog is simply pausing while hidden by another activity - * or when configuration changes. - * If this is false, then we can safely finish this activity if a dialog - * gets dismissed. - */ - private boolean mIsPausing = false; - - EditText mEditText; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (debug) Log.d(TAG, "onCreate"); - - Intent i = getIntent(); - if (i != null && savedInstanceState == null) { - if (debug) Log.d(TAG, "new dialog"); - int dialogId = i.getIntExtra(EXTRA_DIALOG_ID, 0); - switch (dialogId) { - case DIALOG_ID_SAVE: - if (debug) Log.i(TAG, "Show Save dialog"); - saveFile(); - break; - case DIALOG_ID_OPEN: - if (debug) Log.i(TAG, "Show Save dialog"); - openFile(); - break; - case DIALOG_ID_NO_FILE_MANAGER_AVAILABLE: - if (debug) Log.i(TAG, "Show no file manager dialog"); - showDialog(DIALOG_ID_NO_FILE_MANAGER_AVAILABLE); - case DIALOG_ID_ALLOW_EXTERNAL_ACCESS: - if (debug) Log.i(TAG, "Show allow access dialog"); - showDialog(DIALOG_ID_ALLOW_EXTERNAL_ACCESS); - break; - case DIALOG_ID_FIRST_TIME_WARNING: - if (debug) Log.i(TAG, "Show first time warning dialog"); - showDialog(DIALOG_ID_FIRST_TIME_WARNING); - break; - } - } - } - - - /** - * - */ - private void saveFile() { - - // Check whether intent exists - Intent intent = new Intent(FileManagerIntents.ACTION_PICK_FILE); - intent.setData(getIntent().getData()); - if (IntentUtils.isIntentAvailable(this, intent)) { - /* + private static final String TAG = "DialogHostingActivity"; + private static final boolean debug = false; + + public static final int DIALOG_ID_SAVE = 1; + public static final int DIALOG_ID_OPEN = 2; + public static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 3; + public static final int DIALOG_ID_ALLOW_EXTERNAL_ACCESS = 4; + public static final int DIALOG_ID_FIRST_TIME_WARNING = 5; + + public static final String EXTRA_DIALOG_ID = "org.openintents.notepad.extra.dialog_id"; + + /** + * Whether dialog is simply pausing while hidden by another activity + * or when configuration changes. + * If this is false, then we can safely finish this activity if a dialog + * gets dismissed. + */ + private boolean mIsPausing = false; + + EditText mEditText; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (debug) { + Log.d(TAG, "onCreate"); + } + + Intent i = getIntent(); + if (i != null && savedInstanceState == null) { + if (debug) { + Log.d(TAG, "new dialog"); + } + int dialogId = i.getIntExtra(EXTRA_DIALOG_ID, 0); + switch (dialogId) { + case DIALOG_ID_SAVE: + if (debug) { + Log.i(TAG, "Show Save dialog"); + } + saveFile(); + break; + case DIALOG_ID_OPEN: + if (debug) { + Log.i(TAG, "Show Save dialog"); + } + openFile(); + break; + case DIALOG_ID_NO_FILE_MANAGER_AVAILABLE: + if (debug) { + Log.i(TAG, "Show no file manager dialog"); + } + showDialog(DIALOG_ID_NO_FILE_MANAGER_AVAILABLE); + case DIALOG_ID_ALLOW_EXTERNAL_ACCESS: + if (debug) { + Log.i(TAG, "Show allow access dialog"); + } + showDialog(DIALOG_ID_ALLOW_EXTERNAL_ACCESS); + break; + case DIALOG_ID_FIRST_TIME_WARNING: + if (debug) { + Log.i(TAG, "Show first time warning dialog"); + } + showDialog(DIALOG_ID_FIRST_TIME_WARNING); + break; + } + } + } + + /** + * + */ + private void saveFile() { + + // Check whether intent exists + Intent intent = new Intent(FileManagerIntents.ACTION_PICK_FILE); + intent.setData(getIntent().getData()); + if (IntentUtils.isIntentAvailable(this, intent)) { + /* intent.putExtra(NotePadIntents.EXTRA_URI, getIntent().getStringExtra(NotePadIntents.EXTRA_URI)); intent.putExtra(FileManagerIntents.EXTRA_TITLE, getText(R.string.menu_save_to_sdcard)); intent.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT, getText(R.string.save)); */ - intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); - startActivity(intent); - finish(); - } else { - showDialog(DIALOG_ID_SAVE); - } - } - - - private void openFile() { - - // Check whether intent exists - Intent intent = new Intent(FileManagerIntents.ACTION_PICK_FILE); - intent.setData(getIntent().getData()); - if (IntentUtils.isIntentAvailable(this, intent)) { + intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); + startActivity(intent); + finish(); + } else { + showDialog(DIALOG_ID_SAVE); + } + } + + private void openFile() { + + // Check whether intent exists + Intent intent = new Intent(FileManagerIntents.ACTION_PICK_FILE); + intent.setData(getIntent().getData()); + if (IntentUtils.isIntentAvailable(this, intent)) { /* intent.putExtra(NotePadIntents.EXTRA_URI, getIntent().getStringExtra(NotePadIntents.EXTRA_URI)); intent.putExtra(FileManagerIntents.EXTRA_TITLE, getText(R.string.menu_open_from_sdcard)); intent.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT, getText(R.string.open)); intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); */ - startActivity(intent); - finish(); - } else { - showDialog(DIALOG_ID_OPEN); - } - } - - @Override - protected Dialog onCreateDialog(int id) { - if (debug) Log.d(TAG, "onCreateDialog"); - - Dialog dialog = null; - - switch (id) { - case DIALOG_ID_SAVE: - dialog = new FilenameDialog(this); - break; - case DIALOG_ID_OPEN: - dialog = new FilenameDialog(this); - break; - case DIALOG_ID_NO_FILE_MANAGER_AVAILABLE: - if (debug) Log.i(TAG, "fmd - create"); - dialog = new DownloadOIAppDialog(this, - DownloadOIAppDialog.OI_FILEMANAGER); - break; - case DIALOG_ID_ALLOW_EXTERNAL_ACCESS: - dialog = new AllowExternalAccessDialog(this); - break; - case DIALOG_ID_FIRST_TIME_WARNING: - dialog = new FirstTimeWarningDialog(this); - break; - } - if (dialog == null) { - dialog = super.onCreateDialog(id); - } - if (dialog != null) { - dialog.setOnDismissListener(mDismissListener); - } - return dialog; - } - - @Override - protected void onPrepareDialog(int id, Dialog dialog) { - super.onPrepareDialog(id, dialog); - - if (debug) Log.d(TAG, "onPrepareDialog"); - - //dialog.setOnDismissListener(mDismissListener); - - switch (id) { - case DIALOG_ID_SAVE: - break; - case DIALOG_ID_OPEN: - break; - case DIALOG_ID_NO_FILE_MANAGER_AVAILABLE: - DownloadOIAppDialog.onPrepareDialog(this, dialog); - break; - } - } - - OnDismissListener mDismissListener = new OnDismissListener() { - - public void onDismiss(DialogInterface dialoginterface) { - if (debug) Log.d(TAG, "Dialog dismissed. Pausing: " + mIsPausing); - if (!mIsPausing) { - if (debug) Log.d(TAG, "finish"); - // Dialog has been dismissed by user. - DialogHostingActivity.this.finish(); - } else { - // Probably just a screen orientation change. Don't finish yet. - // Dialog has been dismissed by system. - } - } - - }; - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (debug) Log.d(TAG, "onSaveInstanceState"); - // It is important to set mIsPausing here, so that - // the dialog does not get closed on orientation changes. - mIsPausing = true; - if (debug) Log.d(TAG, "onSaveInstanceState. Pausing: " + mIsPausing); - } - - @Override - protected void onResume() { - if (debug) Log.d(TAG, "onResume"); - super.onResume(); - // In case another activity is called, and we are resumed, - // mIsPausing should be reset to its original state. - mIsPausing = false; - } - + startActivity(intent); + finish(); + } else { + showDialog(DIALOG_ID_OPEN); + } + } + + @Override + protected Dialog onCreateDialog(int id) { + if (debug) { + Log.d(TAG, "onCreateDialog"); + } + + Dialog dialog = null; + + switch (id) { + case DIALOG_ID_SAVE: + dialog = new FilenameDialog(this); + break; + case DIALOG_ID_OPEN: + dialog = new FilenameDialog(this); + break; + case DIALOG_ID_NO_FILE_MANAGER_AVAILABLE: + if (debug) { + Log.i(TAG, "fmd - create"); + } + dialog = new DownloadOIAppDialog( + this, + DownloadOIAppDialog.OI_FILEMANAGER + ); + break; + case DIALOG_ID_ALLOW_EXTERNAL_ACCESS: + dialog = new AllowExternalAccessDialog(this); + break; + case DIALOG_ID_FIRST_TIME_WARNING: + dialog = new FirstTimeWarningDialog(this); + break; + } + if (dialog == null) { + dialog = super.onCreateDialog(id); + } + if (dialog != null) { + dialog.setOnDismissListener(mDismissListener); + } + return dialog; + } + + @Override + protected void onPrepareDialog(int id, Dialog dialog) { + super.onPrepareDialog(id, dialog); + + if (debug) { + Log.d(TAG, "onPrepareDialog"); + } + + //dialog.setOnDismissListener(mDismissListener); + + switch (id) { + case DIALOG_ID_SAVE: + break; + case DIALOG_ID_OPEN: + break; + case DIALOG_ID_NO_FILE_MANAGER_AVAILABLE: + DownloadOIAppDialog.onPrepareDialog(this, dialog); + break; + } + } + + OnDismissListener mDismissListener = new OnDismissListener() { + + public void onDismiss(DialogInterface dialoginterface) { + if (debug) { + Log.d(TAG, "Dialog dismissed. Pausing: " + mIsPausing); + } + if (!mIsPausing) { + if (debug) { + Log.d(TAG, "finish"); + } + // Dialog has been dismissed by user. + DialogHostingActivity.this.finish(); + } else { + // Probably just a screen orientation change. Don't finish yet. + // Dialog has been dismissed by system. + } + } + + }; + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (debug) { + Log.d(TAG, "onSaveInstanceState"); + } + // It is important to set mIsPausing here, so that + // the dialog does not get closed on orientation changes. + mIsPausing = true; + if (debug) { + Log.d(TAG, "onSaveInstanceState. Pausing: " + mIsPausing); + } + } + + @Override + protected void onResume() { + if (debug) { + Log.d(TAG, "onResume"); + } + super.onResume(); + // In case another activity is called, and we are resumed, + // mIsPausing should be reset to its original state. + mIsPausing = false; + } + } diff --git a/Safe/src/org/openintents/safe/dialog/FilenameDialog.java b/Safe/src/org/openintents/safe/dialog/FilenameDialog.java index b89de6a5..a48c9d23 100644 --- a/Safe/src/org/openintents/safe/dialog/FilenameDialog.java +++ b/Safe/src/org/openintents/safe/dialog/FilenameDialog.java @@ -1,82 +1,83 @@ package org.openintents.safe.dialog; -import org.openintents.safe.R; - import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; import android.content.DialogInterface.OnClickListener; +import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import android.widget.ImageButton; +import org.openintents.safe.R; + public class FilenameDialog extends AlertDialog implements OnClickListener { // private static final String TAG = "FilenameDialog"; - private static final String BUNDLE_TAGS = "tags"; + private static final String BUNDLE_TAGS = "tags"; - protected static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 2; + protected static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 2; - Context mContext; + Context mContext; - EditText mEditText; + EditText mEditText; - public FilenameDialog(Context context) { - super(context); - mContext = context; + public FilenameDialog(Context context) { + super(context); + mContext = context; - //setTitle(context.getText(R.string.menu_edit_tags)); - setButton(BUTTON_POSITIVE, context.getText(android.R.string.ok), this); - setButton(BUTTON_NEGATIVE, context.getText(android.R.string.cancel), (OnClickListener) null); - setIcon(R.drawable.ic_launcher_folder_small); + //setTitle(context.getText(R.string.menu_edit_tags)); + setButton(BUTTON_POSITIVE, context.getText(android.R.string.ok), this); + setButton(BUTTON_NEGATIVE, context.getText(android.R.string.cancel), (OnClickListener) null); + setIcon(R.drawable.ic_launcher_folder_small); - LayoutInflater inflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.dialog_filename, null); - setView(view); + LayoutInflater inflater = + (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflater.inflate(R.layout.dialog_filename, null); + setView(view); - mEditText = (EditText) view.findViewById(R.id.file_path); + mEditText = (EditText) view.findViewById(R.id.file_path); - //SharedPreferences pm = PreferenceManager.getDefaultSharedPreferences(this); - //mEditText.setText(pm.getString(PREFERENCE_FILENAME, DEFAULT_FILENAME)); + //SharedPreferences pm = PreferenceManager.getDefaultSharedPreferences(this); + //mEditText.setText(pm.getString(PREFERENCE_FILENAME, DEFAULT_FILENAME)); - ImageButton buttonFileManager = (ImageButton) view.findViewById(R.id.file_manager); + ImageButton buttonFileManager = (ImageButton) view.findViewById(R.id.file_manager); - buttonFileManager.setOnClickListener(new View.OnClickListener() { - - public void onClick(View arg0) { - openFileManager(); - } - }); + buttonFileManager.setOnClickListener( + new View.OnClickListener() { - } + public void onClick(View arg0) { + openFileManager(); + } + } + ); + } - public void onClick(DialogInterface dialog, int which) { - if (which == BUTTON_POSITIVE) { - openOrSave(); - } - - } + public void onClick(DialogInterface dialog, int which) { + if (which == BUTTON_POSITIVE) { + openOrSave(); + } - void openOrSave() { - } + } + + void openOrSave() { + } + + private void openFileManager() { + showNoFileManagerAvailableDialog(); - private void openFileManager() { - showNoFileManagerAvailableDialog(); - /* String fileName = mEditText.getText().toString(); Intent intent = new Intent(FileManagerIntents.ACTION_PICK_FILE); intent.setData(Uri.parse("file://" + fileName)); */ - - //intent.putExtra(FileManagerIntents.EXTRA_TITLE, getString(RES_STRING_FILEMANAGER_TITLE)); - //intent.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT, getString(RES_STRING_FILEMANAGER_BUTTON_TEXT)); + + //intent.putExtra(FileManagerIntents.EXTRA_TITLE, getString(RES_STRING_FILEMANAGER_TITLE)); + //intent.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT, getString(RES_STRING_FILEMANAGER_BUTTON_TEXT)); /* try { @@ -85,25 +86,25 @@ private void openFileManager() { mContext.showDialog(DIALOG_ID_NO_FILE_MANAGER_AVAILABLE); } */ - } - - void showNoFileManagerAvailableDialog() { - - Intent i = new Intent(mContext, DialogHostingActivity.class); - i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_NO_FILE_MANAGER_AVAILABLE); - mContext.startActivity(i); - } - - @Override - public Bundle onSaveInstanceState() { - Bundle state = super.onSaveInstanceState(); - state.putString(BUNDLE_TAGS, ""); - return state; - } - - @Override - public void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); + } + + void showNoFileManagerAvailableDialog() { + + Intent i = new Intent(mContext, DialogHostingActivity.class); + i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_NO_FILE_MANAGER_AVAILABLE); + mContext.startActivity(i); + } + + @Override + public Bundle onSaveInstanceState() { + Bundle state = super.onSaveInstanceState(); + state.putString(BUNDLE_TAGS, ""); + return state; + } + + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); // String tags = savedInstanceState.getString(BUNDLE_TAGS); - } + } } diff --git a/Safe/src/org/openintents/safe/dialog/FirstTimeWarningDialog.java b/Safe/src/org/openintents/safe/dialog/FirstTimeWarningDialog.java index b7198b85..6e5620c6 100644 --- a/Safe/src/org/openintents/safe/dialog/FirstTimeWarningDialog.java +++ b/Safe/src/org/openintents/safe/dialog/FirstTimeWarningDialog.java @@ -1,41 +1,40 @@ package org.openintents.safe.dialog; -import org.openintents.safe.R; - import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.widget.CheckBox; +import org.openintents.safe.R; + public class FirstTimeWarningDialog extends AlertDialog implements OnClickListener { // private static final String TAG = "FilenameDialog"; // private static final String BUNDLE_TAGS = "tags"; - protected static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 2; + protected static final int DIALOG_ID_NO_FILE_MANAGER_AVAILABLE = 2; - Context mContext; + Context mContext; - CheckBox mCheckBox; + CheckBox mCheckBox; - public FirstTimeWarningDialog(Context context) { - super(context); - mContext = context; + public FirstTimeWarningDialog(Context context) { + super(context); + mContext = context; - setTitle(context.getText(R.string.dialog_title_first_time_warning)); - setButton(BUTTON_POSITIVE, context.getText(android.R.string.ok), (OnClickListener) null); - //setButton2(context.getText(android.R.string.cancel), (OnClickListener) null); - setIcon(android.R.drawable.ic_dialog_alert); - setMessage(context.getText(R.string.dialog_summary_first_time_warning)); + setTitle(context.getText(R.string.dialog_title_first_time_warning)); + setButton(BUTTON_POSITIVE, context.getText(android.R.string.ok), (OnClickListener) null); + //setButton2(context.getText(android.R.string.cancel), (OnClickListener) null); + setIcon(android.R.drawable.ic_dialog_alert); + setMessage(context.getText(R.string.dialog_summary_first_time_warning)); - } + } + public void onClick(DialogInterface dialog, int which) { + if (which == BUTTON_POSITIVE) { + // User pressed OK + } - public void onClick(DialogInterface dialog, int which) { - if (which == BUTTON_POSITIVE) { - // User pressed OK - } - - } + } } diff --git a/Safe/src/org/openintents/safe/password/Master.java b/Safe/src/org/openintents/safe/password/Master.java index 155ab082..3bde3398 100644 --- a/Safe/src/org/openintents/safe/password/Master.java +++ b/Safe/src/org/openintents/safe/password/Master.java @@ -17,41 +17,39 @@ package org.openintents.safe.password; /** - * Centrally stores the Master Key and Salt for all other classes to use. + * Centrally stores the Master Key and Salt for all other classes to use. */ public class Master { - private static String salt = null; - private static String masterKey = null; + private static String salt = null; + private static String masterKey = null; - /** - * @return the salt - */ - public synchronized static String getSalt() { - return salt; - } + /** + * @return the salt + */ + public synchronized static String getSalt() { + return salt; + } - /** - * @param salt - * the salt to set - */ - public synchronized static void setSalt(String saltIn) { - salt = saltIn; - } + /** + * @param salt the salt to set + */ + public synchronized static void setSalt(String saltIn) { + salt = saltIn; + } - /** - * @return the masterKey - */ - public synchronized static String getMasterKey() { - return masterKey; - } + /** + * @return the masterKey + */ + public synchronized static String getMasterKey() { + return masterKey; + } - /** - * @param masterKey - * the masterKey to set - */ - public synchronized static void setMasterKey(String masterKeyIn) { - masterKey = masterKeyIn; - } + /** + * @param masterKey the masterKey to set + */ + public synchronized static void setMasterKey(String masterKeyIn) { + masterKey = masterKeyIn; + } } diff --git a/Safe/src/org/openintents/safe/service/AutoLockService.java b/Safe/src/org/openintents/safe/service/AutoLockService.java index 6f2a8273..c45bd42b 100644 --- a/Safe/src/org/openintents/safe/service/AutoLockService.java +++ b/Safe/src/org/openintents/safe/service/AutoLockService.java @@ -15,10 +15,6 @@ */ package org.openintents.safe.service; -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.Preferences; -import org.openintents.safe.password.Master; - import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; @@ -30,173 +26,196 @@ import android.preference.PreferenceManager; import android.util.Log; +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.Preferences; +import org.openintents.safe.password.Master; + public class AutoLockService extends Service { - private static final boolean debug = false; - private static String TAG = "AutoLockService"; - - private CountDownTimer t; - private BroadcastReceiver mIntentReceiver; - private static long timeRemaining = 0; - - SharedPreferences mPreferences; - - @Override - public void onCreate() { - if (debug) - Log.d(TAG, "onCreate"); - mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { - if (debug) - Log.d(TAG, "caught ACTION_SCREEN_OFF"); - boolean lockOnScreenLock = mPreferences.getBoolean( - Preferences.PREFERENCE_LOCK_ON_SCREEN_LOCK, true); - if (lockOnScreenLock) { - lockOut(); - } - } else if (intent.getAction().equals( - CryptoIntents.ACTION_RESTART_TIMER)) { - restartTimer(); - } - } - }; - - IntentFilter filter = new IntentFilter(); - filter.addAction(CryptoIntents.ACTION_RESTART_TIMER); - filter.addAction(Intent.ACTION_SCREEN_OFF); - registerReceiver(mIntentReceiver, filter); - - mPreferences = PreferenceManager.getDefaultSharedPreferences(this); - - } - - @Override - public void onStart(Intent intent, int startid) { - if (debug) - Log.d(TAG, "onStart"); - startTimer(); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (debug) - Log.d(TAG, "Received start id " + startId + ": " + intent + ": " - + this); - startTimer(); - // We want this service to continue running until it is explicitly - // stopped, so return sticky. - return START_STICKY; - } - - @Override - public void onDestroy() { - if (debug) - Log.d(TAG, "onDestroy"); - unregisterReceiver(mIntentReceiver); - if (Master.getMasterKey() != null) { - lockOut(); - } - ServiceNotification.clearNotification(AutoLockService.this); - if (t != null) - t.cancel(); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - /** - * Clear the masterKey, notification, and broadcast - * CryptoIntents.ACTION_CRYPTO_LOGGED_OUT - */ - private void lockOut() { - Master.setMasterKey(null); - ServiceNotification.clearNotification(AutoLockService.this); - if (t != null) - t.cancel(); - - Intent intent = new Intent(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); - sendBroadcast(intent); - } - - /** - * Start a CountDownTimer() that will cause a lockOut() - * - * @see #lockOut() - */ - private void startTimer() { - if (Master.getMasterKey() == null) { - ServiceNotification.clearNotification(AutoLockService.this); - if (t != null) - t.cancel(); - return; - } - ServiceNotification.setNotification(AutoLockService.this); - String timeout = mPreferences.getString( - Preferences.PREFERENCE_LOCK_TIMEOUT, - Preferences.PREFERENCE_LOCK_TIMEOUT_DEFAULT_VALUE); - int timeoutMinutes = 5; // default to 5 - try { - timeoutMinutes = Integer.valueOf(timeout); - } catch (NumberFormatException e) { - Log.d(TAG, "why is lock_timeout busted?"); - } - final long timeoutUntilStop = timeoutMinutes * 60000; - - if (debug) - Log.d(TAG, "startTimer with timeoutUntilStop=" + timeoutUntilStop); - - - - t = new CountDownTimer(timeoutUntilStop, 1000) { - - public void onTick(long millisUntilFinished) { - // doing nothing. - if (debug) - Log.d(TAG, "tick: " + millisUntilFinished + " this=" + this); - timeRemaining = millisUntilFinished; - if (Master.getMasterKey() == null) { - if (debug) - Log.d(TAG, "detected masterKey=null"); - lockOut(); - } else { - ServiceNotification.updateProgress(AutoLockService.this, (int)timeoutUntilStop, - (int)timeRemaining); - } - } - - public void onFinish() { - if (debug) - Log.d(TAG, "onFinish()"); - lockOut(); - timeRemaining = 0; - } - }; - t.start(); - timeRemaining = timeoutUntilStop; - if (debug) - Log.d(TAG, "Timer started with: " + timeoutUntilStop); - } - - /** - * Restart the CountDownTimer() - */ - private void restartTimer() { - // must be started with startTimer first. - if (debug) - Log.d(TAG, "timer restarted"); - if (t != null) { - t.cancel(); - t.start(); - } - } - - /** - * @return time remaining in milliseconds before auto lock - */ - public static long getTimeRemaining() { - return timeRemaining; - } -} \ No newline at end of file + private static final boolean debug = false; + private static String TAG = "AutoLockService"; + + private CountDownTimer t; + private BroadcastReceiver mIntentReceiver; + private static long timeRemaining = 0; + + SharedPreferences mPreferences; + + @Override + public void onCreate() { + if (debug) { + Log.d(TAG, "onCreate"); + } + mIntentReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + if (debug) { + Log.d(TAG, "caught ACTION_SCREEN_OFF"); + } + boolean lockOnScreenLock = mPreferences.getBoolean( + Preferences.PREFERENCE_LOCK_ON_SCREEN_LOCK, true + ); + if (lockOnScreenLock) { + lockOut(); + } + } else if (intent.getAction().equals( + CryptoIntents.ACTION_RESTART_TIMER + )) { + restartTimer(); + } + } + }; + + IntentFilter filter = new IntentFilter(); + filter.addAction(CryptoIntents.ACTION_RESTART_TIMER); + filter.addAction(Intent.ACTION_SCREEN_OFF); + registerReceiver(mIntentReceiver, filter); + + mPreferences = PreferenceManager.getDefaultSharedPreferences(this); + + } + + @Override + public void onStart(Intent intent, int startid) { + if (debug) { + Log.d(TAG, "onStart"); + } + startTimer(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (debug) { + Log.d( + TAG, "Received start id " + startId + ": " + intent + ": " + + this + ); + } + startTimer(); + // We want this service to continue running until it is explicitly + // stopped, so return sticky. + return START_STICKY; + } + + @Override + public void onDestroy() { + if (debug) { + Log.d(TAG, "onDestroy"); + } + unregisterReceiver(mIntentReceiver); + if (Master.getMasterKey() != null) { + lockOut(); + } + ServiceNotification.clearNotification(AutoLockService.this); + if (t != null) { + t.cancel(); + } + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + /** + * Clear the masterKey, notification, and broadcast + * CryptoIntents.ACTION_CRYPTO_LOGGED_OUT + */ + private void lockOut() { + Master.setMasterKey(null); + ServiceNotification.clearNotification(AutoLockService.this); + if (t != null) { + t.cancel(); + } + + Intent intent = new Intent(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); + sendBroadcast(intent); + } + + /** + * Start a CountDownTimer() that will cause a lockOut() + * + * @see #lockOut() + */ + private void startTimer() { + if (Master.getMasterKey() == null) { + ServiceNotification.clearNotification(AutoLockService.this); + if (t != null) { + t.cancel(); + } + return; + } + ServiceNotification.setNotification(AutoLockService.this); + String timeout = mPreferences.getString( + Preferences.PREFERENCE_LOCK_TIMEOUT, + Preferences.PREFERENCE_LOCK_TIMEOUT_DEFAULT_VALUE + ); + int timeoutMinutes = 5; // default to 5 + try { + timeoutMinutes = Integer.valueOf(timeout); + } catch (NumberFormatException e) { + Log.d(TAG, "why is lock_timeout busted?"); + } + final long timeoutUntilStop = timeoutMinutes * 60000; + + if (debug) { + Log.d(TAG, "startTimer with timeoutUntilStop=" + timeoutUntilStop); + } + + t = new CountDownTimer(timeoutUntilStop, 1000) { + + public void onTick(long millisUntilFinished) { + // doing nothing. + if (debug) { + Log.d(TAG, "tick: " + millisUntilFinished + " this=" + this); + } + timeRemaining = millisUntilFinished; + if (Master.getMasterKey() == null) { + if (debug) { + Log.d(TAG, "detected masterKey=null"); + } + lockOut(); + } else { + ServiceNotification.updateProgress( + AutoLockService.this, (int) timeoutUntilStop, + (int) timeRemaining + ); + } + } + + public void onFinish() { + if (debug) { + Log.d(TAG, "onFinish()"); + } + lockOut(); + timeRemaining = 0; + } + }; + t.start(); + timeRemaining = timeoutUntilStop; + if (debug) { + Log.d(TAG, "Timer started with: " + timeoutUntilStop); + } + } + + /** + * Restart the CountDownTimer() + */ + private void restartTimer() { + // must be started with startTimer first. + if (debug) { + Log.d(TAG, "timer restarted"); + } + if (t != null) { + t.cancel(); + t.start(); + } + } + + /** + * @return time remaining in milliseconds before auto lock + */ + public static long getTimeRemaining() { + return timeRemaining; + } +} diff --git a/Safe/src/org/openintents/safe/service/ServiceNotification.java b/Safe/src/org/openintents/safe/service/ServiceNotification.java index 657c6cde..79a9e02c 100644 --- a/Safe/src/org/openintents/safe/service/ServiceNotification.java +++ b/Safe/src/org/openintents/safe/service/ServiceNotification.java @@ -15,11 +15,6 @@ */ package org.openintents.safe.service; -import org.openintents.safe.LogOffActivity; -import org.openintents.safe.R; -import org.openintents.safe.wrappers.CheckWrappers; -import org.openintents.safe.wrappers.icecreamsandwich.WrapNotificationBuilder; - import android.annotation.SuppressLint; import android.app.NotificationManager; import android.app.PendingIntent; @@ -30,18 +25,23 @@ import android.support.v4.app.NotificationCompat.Builder; import android.util.Log; +import org.openintents.safe.LogOffActivity; +import org.openintents.safe.R; +import org.openintents.safe.wrappers.CheckWrappers; +import org.openintents.safe.wrappers.icecreamsandwich.WrapNotificationBuilder; + public class ServiceNotification { - private static final boolean debug = true; - private static String TAG = "ServiceNotification"; + private static final boolean debug = true; + private static String TAG = "ServiceNotification"; - private static final int NOTIFICATION_ID = 1; + private static final int NOTIFICATION_ID = 1; - static NotificationManager mNotifyManager; - static WrapNotificationBuilder wrapBuilder; - static Builder notificationCompat; + static NotificationManager mNotifyManager; + static WrapNotificationBuilder wrapBuilder; + static Builder notificationCompat; /* - * public static void updateNotification(Context context) { + * public static void updateNotification(Context context) { * SharedPreferences prefs = PreferenceManager * .getDefaultSharedPreferences(context); //if * (prefs.getBoolean(PreferenceActivity.PREFS_SHOW_NOTIFICATION, false)) { @@ -54,72 +54,81 @@ public class ServiceNotification { * } */ - @SuppressLint("NewApi") - public static void setNotification(Context context) { + @SuppressLint("NewApi") + public static void setNotification(Context context) { - // look up the notification manager service - mNotifyManager = (NotificationManager) context - .getSystemService(Context.NOTIFICATION_SERVICE); + // look up the notification manager service + mNotifyManager = (NotificationManager) context + .getSystemService(Context.NOTIFICATION_SERVICE); - Intent intent = new Intent(context, LogOffActivity.class); - PendingIntent pi = PendingIntent.getActivity(context, 0, intent, - PendingIntent.FLAG_CANCEL_CURRENT); - // Set the info for the views that show in the notification - // panel. - if (debug) - Log.d(TAG, "builder=" + CheckWrappers.mNotificationBuilderAvailable); - if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) - || (CheckWrappers.mNotificationBuilderAvailable == false)) { - notificationCompat = new NotificationCompat.Builder(context) - .setContentTitle(context.getString(R.string.app_name)) - .setContentText( - context.getString(R.string.notification_msg)) - .setSmallIcon(R.drawable.passicon).setOngoing(true) - .setContentIntent(pi); + Intent intent = new Intent(context, LogOffActivity.class); + PendingIntent pi = PendingIntent.getActivity( + context, 0, intent, + PendingIntent.FLAG_CANCEL_CURRENT + ); + // Set the info for the views that show in the notification + // panel. + if (debug) { + Log.d(TAG, "builder=" + CheckWrappers.mNotificationBuilderAvailable); + } + if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) + || (CheckWrappers.mNotificationBuilderAvailable == false)) { + notificationCompat = new NotificationCompat.Builder(context) + .setContentTitle(context.getString(R.string.app_name)) + .setContentText( + context.getString(R.string.notification_msg) + ) + .setSmallIcon(R.drawable.passicon).setOngoing(true) + .setContentIntent(pi); - mNotifyManager.notify(NOTIFICATION_ID, notificationCompat.build()); - } else { - if (debug) Log.d(TAG,"we have progress"); - // The NotificationCompat library doesn't really have a - // setProgress(), so only do - // that for Ice Cream Sandwich and above - wrapBuilder = new WrapNotificationBuilder( - context); - wrapBuilder.setContentTitle(context.getString(R.string.app_name)); - wrapBuilder.setContentText(context - .getString(R.string.notification_msg)); - wrapBuilder.setSmallIcon(R.drawable.passicon); - wrapBuilder.setOngoing(true); - wrapBuilder.setContentIntent(pi); - wrapBuilder.setProgress(100, 0, false); - wrapBuilder.notifyManager(mNotifyManager, NOTIFICATION_ID); - } - } + mNotifyManager.notify(NOTIFICATION_ID, notificationCompat.build()); + } else { + if (debug) { + Log.d(TAG, "we have progress"); + } + // The NotificationCompat library doesn't really have a + // setProgress(), so only do + // that for Ice Cream Sandwich and above + wrapBuilder = new WrapNotificationBuilder( + context + ); + wrapBuilder.setContentTitle(context.getString(R.string.app_name)); + wrapBuilder.setContentText( + context + .getString(R.string.notification_msg) + ); + wrapBuilder.setSmallIcon(R.drawable.passicon); + wrapBuilder.setOngoing(true); + wrapBuilder.setContentIntent(pi); + wrapBuilder.setProgress(100, 0, false); + wrapBuilder.notifyManager(mNotifyManager, NOTIFICATION_ID); + } + } - public static void clearNotification(Context context) { + public static void clearNotification(Context context) { - // look up the notification manager service - NotificationManager nm = (NotificationManager) context - .getSystemService(Context.NOTIFICATION_SERVICE); - nm.cancel(NOTIFICATION_ID); - } + // look up the notification manager service + NotificationManager nm = (NotificationManager) context + .getSystemService(Context.NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } - /** - * Update the existing notification progress bar. This should start with - * progress == max and progress decreasing over time to depict time running - * out. - * - * @param context - * @param max - * @param progress - */ - @SuppressLint("NewApi") - public static void updateProgress(Context context, int max, int progress) { - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) && - (CheckWrappers.mNotificationBuilderAvailable==true)) { - wrapBuilder.setProgress(max, progress, false); - wrapBuilder.notifyManager(mNotifyManager, NOTIFICATION_ID); - } - - } + /** + * Update the existing notification progress bar. This should start with + * progress == max and progress decreasing over time to depict time running + * out. + * + * @param context + * @param max + * @param progress + */ + @SuppressLint("NewApi") + public static void updateProgress(Context context, int max, int progress) { + if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) && + (CheckWrappers.mNotificationBuilderAvailable == true)) { + wrapBuilder.setProgress(max, progress, false); + wrapBuilder.notifyManager(mNotifyManager, NOTIFICATION_ID); + } + + } } diff --git a/Safe/src/org/openintents/safe/wrappers/CheckWrappers.java b/Safe/src/org/openintents/safe/wrappers/CheckWrappers.java index d3c3eec1..892d99f2 100644 --- a/Safe/src/org/openintents/safe/wrappers/CheckWrappers.java +++ b/Safe/src/org/openintents/safe/wrappers/CheckWrappers.java @@ -5,21 +5,21 @@ public class CheckWrappers { - public static boolean mActionBarAvailable; - public static boolean mNotificationBuilderAvailable; - - static { - try { - WrapActionBar.checkAvailable(); - mActionBarAvailable = true; - } catch(Throwable t){ - mActionBarAvailable = false; - } - try { - WrapNotificationBuilder.checkAvailable(); - mNotificationBuilderAvailable = true; - } catch(Throwable t){ - mNotificationBuilderAvailable = false; - } - } + public static boolean mActionBarAvailable; + public static boolean mNotificationBuilderAvailable; + + static { + try { + WrapActionBar.checkAvailable(); + mActionBarAvailable = true; + } catch (Throwable t) { + mActionBarAvailable = false; + } + try { + WrapNotificationBuilder.checkAvailable(); + mNotificationBuilderAvailable = true; + } catch (Throwable t) { + mNotificationBuilderAvailable = false; + } + } } diff --git a/Safe/src/org/openintents/safe/wrappers/honeycomb/ClipboardManager.java b/Safe/src/org/openintents/safe/wrappers/honeycomb/ClipboardManager.java index 9fb8767a..82cb85f6 100644 --- a/Safe/src/org/openintents/safe/wrappers/honeycomb/ClipboardManager.java +++ b/Safe/src/org/openintents/safe/wrappers/honeycomb/ClipboardManager.java @@ -54,7 +54,7 @@ * class that manages copying data to and from the system clipboard. This * provides a wrapper around the API-specific versions of the class to return * the proper object for the platform we're currently running on. - * + *

* Originally from https://code.google.com/p/android-ppp/ * Refactored by Randy McEoin * @@ -62,135 +62,146 @@ */ public abstract class ClipboardManager { - /** A reference to our calling application. We need this to get the - * context and thus the system clipboard services. */ - protected static Application theApp; - - /** - * Sets the contents of the clipboard to the specified text. - * @param text The text to place on the clipboard - */ - public abstract void setText(CharSequence text); - - public abstract boolean hasText(); - - public abstract CharSequence getText(); - - /** - * Get the appropriate instance of the clipboard manager for the - * current Android platform. - * @param app A reference to the calling application - * @return The clipboard manager for the current platform. - */ - public static ClipboardManager newInstance(Application app) - { - // Take note of the app: - theApp = app; - - // If the API number is less than Honeycomb (Android 3.0, or API 11), - // return the old clipboard manager. Otherwise, get the newer version. - // This should be safe because the compiler hard-codes the version - // code during compilation. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) - return new OldClipboardManager(); - else return new HoneycombClipboardManager(); - } - - /** - * The old ClipboardManager, which is a under android.text. This is - * the version to use for all Android versions less than 3.0. - * - * @author Jeffrey T. Darlington - */ - private static class OldClipboardManager extends ClipboardManager { - - /** The actual ClipboardManager object */ - @SuppressWarnings("deprecation") - private static android.text.ClipboardManager clippy = null; - - /** Our constructor */ - @SuppressWarnings("deprecation") - public OldClipboardManager() - { - clippy = (android.text.ClipboardManager)theApp.getSystemService( - android.content.Context.CLIPBOARD_SERVICE); - } - - @SuppressWarnings("deprecation") - @Override - public void setText(CharSequence text) - { - clippy.setText(text); - } - - @SuppressWarnings("deprecation") - @Override - public boolean hasText() - { - return clippy.hasText(); - } - - @SuppressWarnings("deprecation") - @Override - public CharSequence getText() - { - return clippy.getText(); - } - - } - - /** - * The Honeycomb-and-up version of the clipboard manager, this time derived from - * android.content. This version technically supports more content types than - * just text, but we frankly don't care about that in PPP. We just want to make - * sure that when the deprecated android.text.ClipboardManager class finally goes - * away, our application won't break. - * - * @author Jeffrey T. Darlington - */ - @TargetApi(11) private static class HoneycombClipboardManager extends ClipboardManager { - - /** The actual ClipboardManager object */ - private static android.content.ClipboardManager clippy = null; - /** The ClipData object into which we'll put the text */ - private static android.content.ClipData clipData = null; - - /** Our constructor */ - public HoneycombClipboardManager() - { - clippy = (android.content.ClipboardManager)theApp.getSystemService( - android.content.Context.CLIPBOARD_SERVICE); - } - - @Override - public void setText(CharSequence text) - { - clipData = android.content.ClipData.newPlainText( - android.content.ClipDescription.MIMETYPE_TEXT_PLAIN, text); - clippy.setPrimaryClip(clipData); - } - - @Override - public boolean hasText() - { - return clippy.hasPrimaryClip(); - } - - @Override - public CharSequence getText() - { - if (clippy.hasPrimaryClip()) { - ClipData.Item item = clippy.getPrimaryClip().getItemAt(0); - CharSequence pasteData = item.getText(); - if (pasteData==null) { - pasteData=""; - } - return pasteData; - } else { - return ""; - } - } - - } - -} \ No newline at end of file + /** + * A reference to our calling application. We need this to get the + * context and thus the system clipboard services. + */ + protected static Application theApp; + + /** + * Sets the contents of the clipboard to the specified text. + * + * @param text The text to place on the clipboard + */ + public abstract void setText(CharSequence text); + + public abstract boolean hasText(); + + public abstract CharSequence getText(); + + /** + * Get the appropriate instance of the clipboard manager for the + * current Android platform. + * + * @param app A reference to the calling application + * @return The clipboard manager for the current platform. + */ + public static ClipboardManager newInstance(Application app) { + // Take note of the app: + theApp = app; + + // If the API number is less than Honeycomb (Android 3.0, or API 11), + // return the old clipboard manager. Otherwise, get the newer version. + // This should be safe because the compiler hard-codes the version + // code during compilation. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + return new OldClipboardManager(); + } else { + return new HoneycombClipboardManager(); + } + } + + /** + * The old ClipboardManager, which is a under android.text. This is + * the version to use for all Android versions less than 3.0. + * + * @author Jeffrey T. Darlington + */ + private static class OldClipboardManager extends ClipboardManager { + + /** + * The actual ClipboardManager object + */ + @SuppressWarnings("deprecation") + private static android.text.ClipboardManager clippy = null; + + /** + * Our constructor + */ + @SuppressWarnings("deprecation") + public OldClipboardManager() { + clippy = (android.text.ClipboardManager) theApp.getSystemService( + android.content.Context.CLIPBOARD_SERVICE + ); + } + + @SuppressWarnings("deprecation") + @Override + public void setText(CharSequence text) { + clippy.setText(text); + } + + @SuppressWarnings("deprecation") + @Override + public boolean hasText() { + return clippy.hasText(); + } + + @SuppressWarnings("deprecation") + @Override + public CharSequence getText() { + return clippy.getText(); + } + + } + + /** + * The Honeycomb-and-up version of the clipboard manager, this time derived from + * android.content. This version technically supports more content types than + * just text, but we frankly don't care about that in PPP. We just want to make + * sure that when the deprecated android.text.ClipboardManager class finally goes + * away, our application won't break. + * + * @author Jeffrey T. Darlington + */ + @TargetApi(11) + private static class HoneycombClipboardManager extends ClipboardManager { + + /** + * The actual ClipboardManager object + */ + private static android.content.ClipboardManager clippy = null; + /** + * The ClipData object into which we'll put the text + */ + private static android.content.ClipData clipData = null; + + /** + * Our constructor + */ + public HoneycombClipboardManager() { + clippy = (android.content.ClipboardManager) theApp.getSystemService( + android.content.Context.CLIPBOARD_SERVICE + ); + } + + @Override + public void setText(CharSequence text) { + clipData = android.content.ClipData.newPlainText( + android.content.ClipDescription.MIMETYPE_TEXT_PLAIN, text + ); + clippy.setPrimaryClip(clipData); + } + + @Override + public boolean hasText() { + return clippy.hasPrimaryClip(); + } + + @Override + public CharSequence getText() { + if (clippy.hasPrimaryClip()) { + ClipData.Item item = clippy.getPrimaryClip().getItemAt(0); + CharSequence pasteData = item.getText(); + if (pasteData == null) { + pasteData = ""; + } + return pasteData; + } else { + return ""; + } + } + + } + +} diff --git a/Safe/src/org/openintents/safe/wrappers/honeycomb/WrapActionBar.java b/Safe/src/org/openintents/safe/wrappers/honeycomb/WrapActionBar.java index 467dd4ea..464e12b8 100644 --- a/Safe/src/org/openintents/safe/wrappers/honeycomb/WrapActionBar.java +++ b/Safe/src/org/openintents/safe/wrappers/honeycomb/WrapActionBar.java @@ -5,42 +5,42 @@ import android.view.MenuItem; public class WrapActionBar { - private ActionBar mInstance; - - static { - try { - Class.forName("android.app.ActionBar"); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - /* calling here forces class initialization */ - public static void checkAvailable() { - } - - public WrapActionBar(Activity a) { - mInstance = a.getActionBar(); - } - - public void setDisplayHomeAsUpEnabled(boolean b) { - if (mInstance != null) { - mInstance.setDisplayHomeAsUpEnabled(b); - } - } - - public void setHomeButtonEnabled(boolean b) { - if (mInstance != null) { - mInstance.setHomeButtonEnabled(b); - } - } - - // show an icon in the actionbar if there is room for it. - public static void showIfRoom(MenuItem item) { - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - } - - public static void invalidateOptionsMenu(Activity a) { - a.invalidateOptionsMenu(); - } + private ActionBar mInstance; + + static { + try { + Class.forName("android.app.ActionBar"); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + /* calling here forces class initialization */ + public static void checkAvailable() { + } + + public WrapActionBar(Activity a) { + mInstance = a.getActionBar(); + } + + public void setDisplayHomeAsUpEnabled(boolean b) { + if (mInstance != null) { + mInstance.setDisplayHomeAsUpEnabled(b); + } + } + + public void setHomeButtonEnabled(boolean b) { + if (mInstance != null) { + mInstance.setHomeButtonEnabled(b); + } + } + + // show an icon in the actionbar if there is room for it. + public static void showIfRoom(MenuItem item) { + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + } + + public static void invalidateOptionsMenu(Activity a) { + a.invalidateOptionsMenu(); + } } diff --git a/Safe/src/org/openintents/safe/wrappers/icecreamsandwich/WrapNotificationBuilder.java b/Safe/src/org/openintents/safe/wrappers/icecreamsandwich/WrapNotificationBuilder.java index 7b864fd4..3110871f 100644 --- a/Safe/src/org/openintents/safe/wrappers/icecreamsandwich/WrapNotificationBuilder.java +++ b/Safe/src/org/openintents/safe/wrappers/icecreamsandwich/WrapNotificationBuilder.java @@ -29,59 +29,58 @@ * it, nothing shows even on ICS. Thus use a wrapper for the real API here and * over in ServiceNotification, if less than ICS, use * NotificationCompat.Builder. - * */ @SuppressLint("NewApi") public class WrapNotificationBuilder { - private Builder mInstance; + private Builder mInstance; - static { - try { - Class.forName("android.app.Notification$Builder"); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } + static { + try { + Class.forName("android.app.Notification$Builder"); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } - /* calling here forces class initialization */ - public static void checkAvailable() { - } + /* calling here forces class initialization */ + public static void checkAvailable() { + } - public WrapNotificationBuilder(Context context) { - mInstance = new Notification.Builder(context); - } + public WrapNotificationBuilder(Context context) { + mInstance = new Notification.Builder(context); + } - public Builder GetBuilder() { - return mInstance; - } + public Builder GetBuilder() { + return mInstance; + } - public void setContentTitle(CharSequence title) { - mInstance.setContentTitle(title); - } + public void setContentTitle(CharSequence title) { + mInstance.setContentTitle(title); + } - public void setContentText(CharSequence text) { - mInstance.setContentText(text); - } + public void setContentText(CharSequence text) { + mInstance.setContentText(text); + } - public void setSmallIcon(int icon) { - mInstance.setSmallIcon(icon); - } + public void setSmallIcon(int icon) { + mInstance.setSmallIcon(icon); + } - public void setOngoing(boolean ongoing) { - mInstance.setOngoing(ongoing); - } + public void setOngoing(boolean ongoing) { + mInstance.setOngoing(ongoing); + } - public void setContentIntent(PendingIntent intent) { - mInstance.setContentIntent(intent); - } + public void setContentIntent(PendingIntent intent) { + mInstance.setContentIntent(intent); + } - public void setProgress(int max, int progress, boolean indeterminate) { - mInstance.setProgress(max, progress, indeterminate); - } + public void setProgress(int max, int progress, boolean indeterminate) { + mInstance.setProgress(max, progress, indeterminate); + } - @SuppressWarnings("deprecation") - public void notifyManager(NotificationManager nm, int id) { - nm.notify(id, mInstance.getNotification()); - } + @SuppressWarnings("deprecation") + public void notifyManager(NotificationManager nm, int id) { + nm.notify(id, mInstance.getNotification()); + } } diff --git a/Safe/src/org/openintents/util/SecureDelete.java b/Safe/src/org/openintents/util/SecureDelete.java index 485c68b7..97b1c6b3 100644 --- a/Safe/src/org/openintents/util/SecureDelete.java +++ b/Safe/src/org/openintents/util/SecureDelete.java @@ -1,5 +1,7 @@ package org.openintents.util; +import android.util.Log; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -11,74 +13,78 @@ import estreamj.ciphers.trivium.Trivium; import estreamj.framework.ESJException; -import android.util.Log; - /** * Secure file delete. - * - * @author Peli * + * @author Peli */ public class SecureDelete { - private static final String TAG = "SecureDelete"; + private static final String TAG = "SecureDelete"; + + /** + * Securely delete a file. + *

+ * Currently, there is only 1 pass that overwrites the file first + * with a random bit stream generated by Trivium. + * + * @param file + * @return true if this File was deleted, false otherwise. + */ + public static boolean delete(File file) { + + if (file.exists()) { + SecureRandom random = new SecureRandom(); + + Trivium tri = new Trivium(); - /** - * Securely delete a file. - * - * Currently, there is only 1 pass that overwrites the file first - * with a random bit stream generated by Trivium. - * - * @param file - * @return true if this File was deleted, false otherwise. - */ - public static boolean delete(File file) { + try { + RandomAccessFile raf = new RandomAccessFile(file, "rw"); + FileChannel channel = raf.getChannel(); + MappedByteBuffer buffer = channel.map( + FileChannel.MapMode.READ_WRITE, 0, raf.length() + ); - if (file.exists()) { - SecureRandom random = new SecureRandom(); + byte[] key = new byte[10]; + byte[] nonce = new byte[10]; + random.nextBytes(key); + random.nextBytes(nonce); - Trivium tri = new Trivium(); - - try { - RandomAccessFile raf = new RandomAccessFile(file, "rw"); - FileChannel channel = raf.getChannel(); - MappedByteBuffer buffer = channel.map( - FileChannel.MapMode.READ_WRITE, 0, raf.length()); + tri.setupKey( + Trivium.MODE_DECRYPT, + key, 0 + ); + tri.setupNonce(nonce, 0); - byte[] key = new byte[10]; - byte[] nonce = new byte[10]; - random.nextBytes(key); - random.nextBytes(nonce); - - tri.setupKey(Trivium.MODE_DECRYPT, - key, 0); - tri.setupNonce(nonce, 0); + int buffersize = 1024; + byte[] bytes = new byte[1024]; - int buffersize = 1024; - byte[] bytes = new byte[1024]; - - // overwrite with random numbers - while (buffer.hasRemaining()) { - int max = buffer.limit() - buffer.position(); - if (max > buffersize) max = buffersize; - //random.nextBytes(bytes); + // overwrite with random numbers + while (buffer.hasRemaining()) { + int max = buffer.limit() - buffer.position(); + if (max > buffersize) { + max = buffersize; + } + //random.nextBytes(bytes); - tri.process(bytes, 0, - bytes, 0, max); + tri.process( + bytes, 0, + bytes, 0, max + ); - buffer.put(bytes, 0, max); - } - buffer.force(); - buffer.rewind(); + buffer.put(bytes, 0, max); + } + buffer.force(); + buffer.rewind(); - } catch (FileNotFoundException e) { - Log.d(TAG, "FileNotFoundException", e); - } catch (IOException e) { - Log.d(TAG, "IOException", e); - } catch (ESJException e) { - Log.d(TAG, "ESJException", e); - } - return file.delete(); - } - return false; - } + } catch (FileNotFoundException e) { + Log.d(TAG, "FileNotFoundException", e); + } catch (IOException e) { + Log.d(TAG, "IOException", e); + } catch (ESJException e) { + Log.d(TAG, "ESJException", e); + } + return file.delete(); + } + return false; + } } diff --git a/SafeDemo/src/org/openintents/intents/CryptoIntents.java b/SafeDemo/src/org/openintents/intents/CryptoIntents.java index 6f5ba4b7..741fc895 100644 --- a/SafeDemo/src/org/openintents/intents/CryptoIntents.java +++ b/SafeDemo/src/org/openintents/intents/CryptoIntents.java @@ -16,116 +16,114 @@ package org.openintents.intents; /** - * @version Jan 11, 2008, 11:50 UTC - * * @author Isaac Potoczny-Jones * @author Peli - * + * @version Jan 11, 2008, 11:50 UTC */ public class CryptoIntents { - /** - * Activity Action: Encrypt all strings given in the extra(s) EXTRA_TEXT or - * EXTRA_TEXT_ARRAY. - * Returns all encrypted string in the same extra(s). - * - *

Constant Value: "org.openintents.action.ENCRYPT"

- */ - public static final String ACTION_ENCRYPT = "org.openintents.action.ENCRYPT"; + /** + * Activity Action: Encrypt all strings given in the extra(s) EXTRA_TEXT or + * EXTRA_TEXT_ARRAY. + * Returns all encrypted string in the same extra(s). + *

+ *

Constant Value: "org.openintents.action.ENCRYPT"

+ */ + public static final String ACTION_ENCRYPT = "org.openintents.action.ENCRYPT"; + + /** + * Activity Action: Decrypt all strings given in the extra TEXT or + * EXTRA_TEXT_ARRAY. + * Returns all decrypted string in the same extra(s). + *

+ *

Constant Value: "org.openintents.action.DECRYPT"

+ */ + public static final String ACTION_DECRYPT = "org.openintents.action.DECRYPT"; + + /** + * Activity Action: Get the password corresponding to the category of the + * calling application, and the EXTRA_DESCRIPTION, as provided. + * Returns the decrypted username & password in the extras EXTRA_USERNAME and + * EXTRA_PASSWORD. CATEGORY is an optional parameter. + *

+ *

Constant Value: "org.openintents.action.GET_PASSWORD"

+ */ + public static final String ACTION_GET_PASSWORD = "org.openintents.action.GET_PASSWORD"; + + /** + * Activity Action: Set the password corresponding to the category of the + * calling application, and the EXTRA_DESCRIPTION, EXTRA_USERNAME and + * EXTRA_PASSWORD as provided. CATEGORY is an optional parameter. + *

+ * If both username and password are the non-null empty string, delete this + * password entry. + *

Constant Value: "org.openintents.action.SET_PASSWORD"

+ */ + public static final String ACTION_SET_PASSWORD = "org.openintents.action.SET_PASSWORD"; + + /** + * Broadcast Action: Sent when the user got logged out of the + * crypto session. + *

+ * This can happen after the user logs out actively, + * or through a time-out. + *

+ * Activities that show decrypted content should hide that content again. + *

+ *

Constant Value: "org.openintents.action.CRYPTO_LOGGED_OUT"

+ */ + public static final String ACTION_CRYPTO_LOGGED_OUT = "org.openintents.action.CRYPTO_LOGGED_OUT"; + + /** + * The text to encrypt or decrypt, or the location for the return result. + *

+ *

Constant Value: "org.openintents.extra.TEXT"

+ */ + public static final String EXTRA_TEXT = "org.openintents.extra.TEXT"; + + /** + * An array of text to encrypt or decrypt, or the location for the return result. + * Use this to encrypt several strings at once. + *

+ * Entries of the array that are null will be simply ignored and not + * encrypted or decrypted. + *

+ *

Constant Value: "org.openintents.extra.TEXT_ARRAY"

+ */ + public static final String EXTRA_TEXT_ARRAY = "org.openintents.extra.TEXT_ARRAY"; - /** - * Activity Action: Decrypt all strings given in the extra TEXT or - * EXTRA_TEXT_ARRAY. - * Returns all decrypted string in the same extra(s). - * - *

Constant Value: "org.openintents.action.DECRYPT"

- */ - public static final String ACTION_DECRYPT = "org.openintents.action.DECRYPT"; - - /** - * Activity Action: Get the password corresponding to the category of the - * calling application, and the EXTRA_DESCRIPTION, as provided. - * Returns the decrypted username & password in the extras EXTRA_USERNAME and - * EXTRA_PASSWORD. CATEGORY is an optional parameter. - * - *

Constant Value: "org.openintents.action.GET_PASSWORD"

- */ - public static final String ACTION_GET_PASSWORD = "org.openintents.action.GET_PASSWORD"; - - /** - * Activity Action: Set the password corresponding to the category of the - * calling application, and the EXTRA_DESCRIPTION, EXTRA_USERNAME and - * EXTRA_PASSWORD as provided. CATEGORY is an optional parameter. - * - * If both username and password are the non-null empty string, delete this - * password entry. - *

Constant Value: "org.openintents.action.SET_PASSWORD"

- */ - public static final String ACTION_SET_PASSWORD = "org.openintents.action.SET_PASSWORD"; + /** + * Required input parameter to GET_PASSWORD and SET_PASSWORD. Corresponds to the "description" + * field in passwordsafe. Should be a unique name for the password you're using, + * and will already be specific to your application, ie "org.syntaxpolice.opensocial" + *

+ *

Constant Value: "org.openintents.extra.UNIQUE_NAME"

+ */ + public static final String EXTRA_UNIQUE_NAME = "org.openintents.extra.UNIQUE_NAME"; - /** - * Broadcast Action: Sent when the user got logged out of the - * crypto session. - * - * This can happen after the user logs out actively, - * or through a time-out. - * - * Activities that show decrypted content should hide that content again. - * - *

Constant Value: "org.openintents.action.CRYPTO_LOGGED_OUT"

- */ - public static final String ACTION_CRYPTO_LOGGED_OUT = "org.openintents.action.CRYPTO_LOGGED_OUT"; - - /** - * The text to encrypt or decrypt, or the location for the return result. - * - *

Constant Value: "org.openintents.extra.TEXT"

- */ - public static final String EXTRA_TEXT = "org.openintents.extra.TEXT"; - - /** - * An array of text to encrypt or decrypt, or the location for the return result. - * Use this to encrypt several strings at once. - * - * Entries of the array that are null will be simply ignored and not - * encrypted or decrypted. - * - *

Constant Value: "org.openintents.extra.TEXT_ARRAY"

- */ - public static final String EXTRA_TEXT_ARRAY = "org.openintents.extra.TEXT_ARRAY"; - - /** - * Required input parameter to GET_PASSWORD and SET_PASSWORD. Corresponds to the "description" - * field in passwordsafe. Should be a unique name for the password you're using, - * and will already be specific to your application, ie "org.syntaxpolice.opensocial" - * - *

Constant Value: "org.openintents.extra.UNIQUE_NAME"

- */ - public static final String EXTRA_UNIQUE_NAME = "org.openintents.extra.UNIQUE_NAME"; + /** + * Output parameter from GET_PASSWORD and optional input parameter to SET_PASSWORD. + * Corresponds to the decrypted "username" field in passwordsafe. + *

+ *

Constant Value: "org.openintents.extra.USERNAME"

+ */ + public static final String EXTRA_USERNAME = "org.openintents.extra.USERNAME"; - /** - * Output parameter from GET_PASSWORD and optional input parameter to SET_PASSWORD. - * Corresponds to the decrypted "username" field in passwordsafe. - * - *

Constant Value: "org.openintents.extra.USERNAME"

- */ - public static final String EXTRA_USERNAME = "org.openintents.extra.USERNAME"; - - /** - * Output parameter from GET_PASSWORD and _required_ input parameter to SET_PASSWORD. - * Corresponds to the decrypted "password" field in passwordsafe. - * - *

Constant Value: "org.openintents.extra.PASSWORD"

- */ - public static final String EXTRA_PASSWORD = "org.openintents.extra.PASSWORD"; + /** + * Output parameter from GET_PASSWORD and _required_ input parameter to SET_PASSWORD. + * Corresponds to the decrypted "password" field in passwordsafe. + *

+ *

Constant Value: "org.openintents.extra.PASSWORD"

+ */ + public static final String EXTRA_PASSWORD = "org.openintents.extra.PASSWORD"; - /** - * Whether to prompt for the password if the service is not running yet. - * - * Default value is 'true'. Set to 'false' if you want to suppress prompting for - * a password. - * - *

Constant Value: "org.openintents.extra.PROMPT"

- */ - public static final String EXTRA_PROMPT = "org.openintents.extra.PROMPT"; + /** + * Whether to prompt for the password if the service is not running yet. + *

+ * Default value is 'true'. Set to 'false' if you want to suppress prompting for + * a password. + *

+ *

Constant Value: "org.openintents.extra.PROMPT"

+ */ + public static final String EXTRA_PROMPT = "org.openintents.extra.PROMPT"; } diff --git a/SafeDemo/src/org/openintents/samples/testsafe/TestSafe.java b/SafeDemo/src/org/openintents/samples/testsafe/TestSafe.java index 6ef8975b..f2146b89 100644 --- a/SafeDemo/src/org/openintents/samples/testsafe/TestSafe.java +++ b/SafeDemo/src/org/openintents/samples/testsafe/TestSafe.java @@ -1,8 +1,5 @@ package org.openintents.samples.testsafe; -import org.openintents.intents.CryptoIntents; -import org.openintents.safe.service.ServiceDispatch; - import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ComponentName; @@ -19,233 +16,261 @@ import android.widget.EditText; import android.widget.Toast; +import org.openintents.intents.CryptoIntents; +import org.openintents.safe.service.ServiceDispatch; + public class TestSafe extends Activity { - public final String TAG="SERVICE_TEST"; - public final Integer ENCRYPT_REQUEST = 1; - public final Integer DECRYPT_REQUEST = 2; - public final Integer GET_PASSWORD_REQUEST = 3; - public final Integer SET_PASSWORD_REQUEST = 4; - public final Integer SPOOF_REQUEST = 5; - public final String desc = "opensocial"; - - - /** Called when the activity is first created. */ + public final String TAG = "SERVICE_TEST"; + public final Integer ENCRYPT_REQUEST = 1; + public final Integer DECRYPT_REQUEST = 2; + public final Integer GET_PASSWORD_REQUEST = 3; + public final Integer SET_PASSWORD_REQUEST = 4; + public final Integer SPOOF_REQUEST = 5; + public final String desc = "opensocial"; + + /** + * Called when the activity is first created. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); - EditText inputText = (EditText) findViewById(R.id.input_entry); - inputText.setText(desc, - android.widget.TextView.BufferType.EDITABLE); - + EditText inputText = (EditText) findViewById(R.id.input_entry); + inputText.setText( + desc, + android.widget.TextView.BufferType.EDITABLE + ); + // ---------------- clicky - Button encryptIntentButton = (Button) findViewById(R.id.encrypti); - Button decryptIntentButton = (Button) findViewById(R.id.decrypti); - Button getButton = (Button) findViewById(R.id.get); - Button setButton = (Button) findViewById(R.id.set); - Button outToInButton = (Button) findViewById(R.id.outToIn); - Button spoofme = (Button) findViewById(R.id.spoof_me); - - encryptIntentButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - clickMaster (ENCRYPT_REQUEST); - }}); - decryptIntentButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - clickMaster (DECRYPT_REQUEST); - }}); - getButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - clickMaster (GET_PASSWORD_REQUEST); - }}); - setButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - clickMaster (SET_PASSWORD_REQUEST); - }}); - //move output text box to input: - outToInButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - EditText outputText = (EditText) findViewById(R.id.output_entry); - EditText inputText = (EditText) findViewById(R.id.input_entry); - String newInputStr = outputText.getText().toString(); - inputText.setText(newInputStr, android.widget.TextView.BufferType.EDITABLE); - - }}); - spoofme.setOnClickListener(new View.OnClickListener() { - public void onClick(View arg0) { - Intent i = new Intent(); - i.setAction(Intent.ACTION_MAIN); - i.setClassName("org.openintents.safe", "org.openintents.safe.AskPassword"); - startActivityForResult(i, SPOOF_REQUEST); - }}); - + Button encryptIntentButton = (Button) findViewById(R.id.encrypti); + Button decryptIntentButton = (Button) findViewById(R.id.decrypti); + Button getButton = (Button) findViewById(R.id.get); + Button setButton = (Button) findViewById(R.id.set); + Button outToInButton = (Button) findViewById(R.id.outToIn); + Button spoofme = (Button) findViewById(R.id.spoof_me); + + encryptIntentButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + clickMaster(ENCRYPT_REQUEST); + } + } + ); + decryptIntentButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + clickMaster(DECRYPT_REQUEST); + } + } + ); + getButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + clickMaster(GET_PASSWORD_REQUEST); + } + } + ); + setButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + clickMaster(SET_PASSWORD_REQUEST); + } + } + ); + //move output text box to input: + outToInButton.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + EditText outputText = (EditText) findViewById(R.id.output_entry); + EditText inputText = (EditText) findViewById(R.id.input_entry); + String newInputStr = outputText.getText().toString(); + inputText.setText(newInputStr, android.widget.TextView.BufferType.EDITABLE); + + } + } + ); + spoofme.setOnClickListener( + new View.OnClickListener() { + public void onClick(View arg0) { + Intent i = new Intent(); + i.setAction(Intent.ACTION_MAIN); + i.setClassName("org.openintents.safe", "org.openintents.safe.AskPassword"); + startActivityForResult(i, SPOOF_REQUEST); + } + } + ); + }//oncreate - private void clickMaster (Integer request) { - CheckBox checkbox = (CheckBox) findViewById(R.id.check_service); - if (checkbox.isChecked()) { - clickMasterService(request); - } else { - clickMasterIntent(request); - } + private void clickMaster(Integer request) { + CheckBox checkbox = (CheckBox) findViewById(R.id.check_service); + if (checkbox.isChecked()) { + clickMasterService(request); + } else { + clickMasterIntent(request); + } } private int serviceRequest; - - private void clickMasterService (Integer request) { - serviceRequest = request; - - initService(); // calls clickMasterServiceDispatch() upon connection - - //releaseService(); + + private void clickMasterService(Integer request) { + serviceRequest = request; + + initService(); // calls clickMasterServiceDispatch() upon connection + + //releaseService(); + } + + private void clickMasterServiceDispatch() { + EditText inputText = (EditText) findViewById(R.id.input_entry); + String inputStr = inputText.getText().toString(); + + try { + String masterKey = service.getPassword(); + String resultText = "?"; + + if (serviceRequest == ENCRYPT_REQUEST) { + resultText = service.encrypt(inputStr); + } else if (serviceRequest == DECRYPT_REQUEST) { + resultText = service.decrypt(inputStr); + } else { + Toast.makeText( + TestSafe.this, + "This is not yet supported!", + Toast.LENGTH_SHORT + ).show(); + } + + EditText outputText = (EditText) findViewById(R.id.output_entry); + outputText.setText(resultText, android.widget.TextView.BufferType.EDITABLE); + } catch (RemoteException e) { + Log.e(TAG, "Remote exception", e); + } } - - private void clickMasterServiceDispatch () { - EditText inputText = (EditText) findViewById(R.id.input_entry); - String inputStr = inputText.getText().toString(); - - try { - String masterKey = service.getPassword(); - String resultText = "?"; - - if (serviceRequest == ENCRYPT_REQUEST) { - resultText = service.encrypt(inputStr); - } else if (serviceRequest == DECRYPT_REQUEST) { - resultText = service.decrypt(inputStr); - } else { - Toast.makeText(TestSafe.this, - "This is not yet supported!", - Toast.LENGTH_SHORT).show(); - } - - EditText outputText = (EditText) findViewById(R.id.output_entry); - outputText.setText(resultText, android.widget.TextView.BufferType.EDITABLE); - } catch (RemoteException e) { - Log.e(TAG, "Remote exception", e); - } - } - - private void clickMasterIntent (Integer request) { - EditText inputText = (EditText) findViewById(R.id.input_entry); - String inputStr = inputText.getText().toString(); - - Intent i = new Intent(); - i.putExtra(CryptoIntents.EXTRA_TEXT, inputStr); - - if (request == ENCRYPT_REQUEST) { + + private void clickMasterIntent(Integer request) { + EditText inputText = (EditText) findViewById(R.id.input_entry); + String inputStr = inputText.getText().toString(); + + Intent i = new Intent(); + i.putExtra(CryptoIntents.EXTRA_TEXT, inputStr); + + if (request == ENCRYPT_REQUEST) { i.setAction(CryptoIntents.ACTION_ENCRYPT); - } else if (request == DECRYPT_REQUEST) { + } else if (request == DECRYPT_REQUEST) { i.setAction(CryptoIntents.ACTION_DECRYPT); - } else if (request == GET_PASSWORD_REQUEST) { - i.putExtra(CryptoIntents.EXTRA_UNIQUE_NAME, inputStr); - i.setAction (CryptoIntents.ACTION_GET_PASSWORD); - } else if (request == SET_PASSWORD_REQUEST) { - String uniqueNameStr = ((EditText) findViewById(R.id.unique_name_entry)).getText().toString(); - String passwordStr = ((EditText) findViewById(R.id.password_entry)).getText().toString(); - String usernameStr = ((EditText) findViewById(R.id.username_entry)).getText().toString(); + } else if (request == GET_PASSWORD_REQUEST) { + i.putExtra(CryptoIntents.EXTRA_UNIQUE_NAME, inputStr); + i.setAction(CryptoIntents.ACTION_GET_PASSWORD); + } else if (request == SET_PASSWORD_REQUEST) { + String uniqueNameStr = ((EditText) findViewById(R.id.unique_name_entry)).getText().toString(); + String passwordStr = ((EditText) findViewById(R.id.password_entry)).getText().toString(); + String usernameStr = ((EditText) findViewById(R.id.username_entry)).getText().toString(); + i.putExtra(CryptoIntents.EXTRA_UNIQUE_NAME, uniqueNameStr); + i.putExtra(CryptoIntents.EXTRA_PASSWORD, passwordStr); + i.putExtra(CryptoIntents.EXTRA_USERNAME, usernameStr); - i.putExtra(CryptoIntents.EXTRA_UNIQUE_NAME, uniqueNameStr); - i.putExtra(CryptoIntents.EXTRA_PASSWORD, passwordStr); - i.putExtra(CryptoIntents.EXTRA_USERNAME, usernameStr); - - i.setAction (CryptoIntents.ACTION_SET_PASSWORD); - } + i.setAction(CryptoIntents.ACTION_SET_PASSWORD); + } try { - startActivityForResult(i, request); + startActivityForResult(i, request); } catch (ActivityNotFoundException e) { - Log.e(TAG, "failed to invoke intent: " + e.toString()); + Log.e(TAG, "failed to invoke intent: " + e.toString()); } } - - protected void onActivityResult (int requestCode, int resultCode, Intent data) { - String resultText = ""; - if (resultCode != RESULT_OK) { - resultText = "An error occured while contacting OI Safe. Does it allow remote access? (Please check in the settings of OI Safe)."; - } else { - if (requestCode == ENCRYPT_REQUEST || requestCode == DECRYPT_REQUEST) { - resultText = data.getStringExtra (CryptoIntents.EXTRA_TEXT); - } else if (requestCode == SET_PASSWORD_REQUEST) { - resultText = "Request to set password sent."; - } else if (requestCode == GET_PASSWORD_REQUEST){ - String uname = data.getStringExtra (CryptoIntents.EXTRA_USERNAME); - String pwd = data.getStringExtra (CryptoIntents.EXTRA_PASSWORD); - resultText = uname + ":" + pwd; - } else if (requestCode == SPOOF_REQUEST) { - resultText = data.getStringExtra("masterKey"); - } - } - EditText outputText = (EditText) findViewById(R.id.output_entry); - outputText.setText(resultText, android.widget.TextView.BufferType.EDITABLE); - } - + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + String resultText = ""; + if (resultCode != RESULT_OK) { + resultText = "An error occured while contacting OI Safe. Does it allow remote access? (Please check in the settings of OI Safe)."; + } else { + if (requestCode == ENCRYPT_REQUEST || requestCode == DECRYPT_REQUEST) { + resultText = data.getStringExtra(CryptoIntents.EXTRA_TEXT); + } else if (requestCode == SET_PASSWORD_REQUEST) { + resultText = "Request to set password sent."; + } else if (requestCode == GET_PASSWORD_REQUEST) { + String uname = data.getStringExtra(CryptoIntents.EXTRA_USERNAME); + String pwd = data.getStringExtra(CryptoIntents.EXTRA_PASSWORD); + resultText = uname + ":" + pwd; + } else if (requestCode == SPOOF_REQUEST) { + resultText = data.getStringExtra("masterKey"); + } + } + EditText outputText = (EditText) findViewById(R.id.output_entry); + outputText.setText(resultText, android.widget.TextView.BufferType.EDITABLE); + } - //--------------------------- service stuff ------------ + //--------------------------- service stuff ------------ - // service elements + // service elements private ServiceDispatch service; private ServiceDispatchConnection conn; - - private void initService() { + + private void initService() { String action = getIntent().getAction(); boolean isLocal = action == null || action.equals(Intent.ACTION_MAIN); - conn = new ServiceDispatchConnection(isLocal); - Intent i = new Intent(); - i.setClassName("org.openintents.safe", "org.openintents.safe.service.ServiceDispatchImpl"); - try { - startService(i); - bindService( i, conn, Context.BIND_AUTO_CREATE); - } catch (SecurityException e) { - Log.e(TAG, "SecurityException", e); - Toast.makeText(TestSafe.this, - "SecurityException: Not allowed to connect!", - Toast.LENGTH_SHORT).show(); - } - } - - private void releaseService() { - if (conn != null ) { - unbindService( conn ); - conn = null; - } - } - - class ServiceDispatchConnection implements ServiceConnection - { - boolean askPassIsLocal = false; - public ServiceDispatchConnection (Boolean isLocal) { - askPassIsLocal = isLocal; - } - public void onServiceConnected(ComponentName className, - IBinder boundService ) - { - service = ServiceDispatch.Stub.asInterface((IBinder)boundService); - - boolean promptforpassword = getIntent().getBooleanExtra(CryptoIntents.EXTRA_PROMPT, true); - - try { - if (service.getPassword() == null) { - - Toast.makeText(TestSafe.this, - "Service not running.", - Toast.LENGTH_SHORT).show(); - } else { - //service already started, so don't need to ask pw. - clickMasterServiceDispatch(); - } - } catch (RemoteException e) { - Log.d(TAG, e.toString()); - } - Log.d( TAG,"onServiceConnected" ); - } - - public void onServiceDisconnected(ComponentName className) - { - service = null; - Log.d( TAG,"onServiceDisconnected" ); - } - }; + conn = new ServiceDispatchConnection(isLocal); + Intent i = new Intent(); + i.setClassName("org.openintents.safe", "org.openintents.safe.service.ServiceDispatchImpl"); + try { + startService(i); + bindService(i, conn, Context.BIND_AUTO_CREATE); + } catch (SecurityException e) { + Log.e(TAG, "SecurityException", e); + Toast.makeText( + TestSafe.this, + "SecurityException: Not allowed to connect!", + Toast.LENGTH_SHORT + ).show(); + } + } + + private void releaseService() { + if (conn != null) { + unbindService(conn); + conn = null; + } + } + + class ServiceDispatchConnection implements ServiceConnection { + boolean askPassIsLocal = false; + + public ServiceDispatchConnection(Boolean isLocal) { + askPassIsLocal = isLocal; + } + + public void onServiceConnected(ComponentName className, + IBinder boundService) { + service = ServiceDispatch.Stub.asInterface((IBinder) boundService); + + boolean promptforpassword = getIntent().getBooleanExtra(CryptoIntents.EXTRA_PROMPT, true); + + try { + if (service.getPassword() == null) { + + Toast.makeText( + TestSafe.this, + "Service not running.", + Toast.LENGTH_SHORT + ).show(); + } else { + //service already started, so don't need to ask pw. + clickMasterServiceDispatch(); + } + } catch (RemoteException e) { + Log.d(TAG, e.toString()); + } + Log.d(TAG, "onServiceConnected"); + } + + public void onServiceDisconnected(ComponentName className) { + service = null; + Log.d(TAG, "onServiceDisconnected"); + } + } + + ; } diff --git a/SafeTest/src/org/openintents/safe/test/SafeTest.java b/SafeTest/src/org/openintents/safe/test/SafeTest.java index d84007c1..921f09b6 100644 --- a/SafeTest/src/org/openintents/safe/test/SafeTest.java +++ b/SafeTest/src/org/openintents/safe/test/SafeTest.java @@ -15,33 +15,32 @@ package org.openintents.safe.test; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.Smoke; +import android.util.Log; + +import com.jayway.android.robotium.solo.Solo; + import org.openintents.safe.CategoryList; import org.openintents.safe.R; -import com.jayway.android.robotium.solo.Solo; +public class SafeTest extends ActivityInstrumentationTestCase2 { -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.Smoke; -import android.util.Log; -import android.widget.Button; + private final String TAG = "SafeTest"; + private final String masterPassword = "1234"; -public class SafeTest extends ActivityInstrumentationTestCase2{ + private Solo solo; - private final String TAG="SafeTest"; - private final String masterPassword="1234"; - - private Solo solo; + public SafeTest() { + super("org.openintents.safe", CategoryList.class); + } - public SafeTest() { - super("org.openintents.safe", CategoryList.class); - } + public void setUp() throws Exception { + solo = new Solo(getInstrumentation(), getActivity()); + } - public void setUp() throws Exception { - solo = new Solo(getInstrumentation(), getActivity()); - } + private void unlockIfNeeded() throws Exception { - private void unlockIfNeeded() throws Exception { - // String confirm = getActivity().getString(R.string.oi_distribution_eula_accept); // if (solo.searchButton(confirm)){ // solo.clickOnButton(confirm); @@ -51,246 +50,246 @@ private void unlockIfNeeded() throws Exception { // if (solo.searchButton(cont)){ // solo.clickOnButton(cont); // } - - - String continueText = getActivity().getString(R.string.continue_text); - String restore = getActivity().getString(R.string.restore); - String firstTime = getActivity().getString(R.string.first_time); - if (solo.searchText(firstTime)){ - Log.d(TAG,"Creating new master password"); - solo.enterText(0, masterPassword); - solo.enterText(1, masterPassword); - solo.clickOnButton(continueText); - - solo.clickOnButton(getActivity().getString(android.R.string.ok)); - - } - - if (solo.searchButton(continueText)) { - Log.d(TAG,"unlocking"); - solo.enterText(0, masterPassword); - solo.clickOnButton(continueText); - } - - } - - private String getAppString(int resId) { - return getActivity().getString(resId); - } - - @Smoke - public void test000Eula() { - String accept = getAppString(org.openintents.distribution.R.string.oi_distribution_eula_accept); - String cancel = getAppString(org.openintents.distribution.R.string.oi_distribution_eula_refuse); - boolean existsAccept = solo.searchButton(accept); - boolean existsCancel = solo.searchButton(cancel); - - if (existsAccept && existsCancel) { - solo.clickOnButton(accept); - } - } - - @Smoke - public void test001RecentChanges() { - String recentChanges = getAppString(org.openintents.distribution.R.string.oi_distribution_newversion_recent_changes); - String cont = getAppString(org.openintents.distribution.R.string.oi_distribution_newversion_continue); - while(solo.scrollUp()); - boolean existsRecentChanges = solo.searchText(recentChanges); - boolean existsCont = solo.searchButton(cont); - - if (existsRecentChanges && existsCont) { - solo.clickOnButton(cont); - } - } - - @Smoke - public void testAAAAUnlock() throws Exception { - unlockIfNeeded(); - - // This test fails in Honeycomb: - //solo.assertCurrentActivity("Expected CategoryList", CategoryList.class); - } - - @Smoke - public void testCategoryAdd() throws Exception { + + String continueText = getActivity().getString(R.string.continue_text); + String restore = getActivity().getString(R.string.restore); + String firstTime = getActivity().getString(R.string.first_time); + if (solo.searchText(firstTime)) { + Log.d(TAG, "Creating new master password"); + solo.enterText(0, masterPassword); + solo.enterText(1, masterPassword); + solo.clickOnButton(continueText); + + solo.clickOnButton(getActivity().getString(android.R.string.ok)); + + } + + if (solo.searchButton(continueText)) { + Log.d(TAG, "unlocking"); + solo.enterText(0, masterPassword); + solo.clickOnButton(continueText); + } + + } + + private String getAppString(int resId) { + return getActivity().getString(resId); + } + + @Smoke + public void test000Eula() { + String accept = getAppString(org.openintents.distribution.R.string.oi_distribution_eula_accept); + String cancel = getAppString(org.openintents.distribution.R.string.oi_distribution_eula_refuse); + boolean existsAccept = solo.searchButton(accept); + boolean existsCancel = solo.searchButton(cancel); + + if (existsAccept && existsCancel) { + solo.clickOnButton(accept); + } + } + + @Smoke + public void test001RecentChanges() { + String recentChanges = getAppString(org.openintents.distribution.R.string.oi_distribution_newversion_recent_changes); + String cont = getAppString(org.openintents.distribution.R.string.oi_distribution_newversion_continue); + while (solo.scrollUp()) { + ; + } + boolean existsRecentChanges = solo.searchText(recentChanges); + boolean existsCont = solo.searchButton(cont); + + if (existsRecentChanges && existsCont) { + solo.clickOnButton(cont); + } + } + + @Smoke + public void testAAAAUnlock() throws Exception { + unlockIfNeeded(); + + // This test fails in Honeycomb: + //solo.assertCurrentActivity("Expected CategoryList", CategoryList.class); + } + + @Smoke + public void testCategoryAdd() throws Exception { // unlockIfNeeded(); - - solo.assertCurrentActivity("Expected CategoryList activity", "CategoryList"); - - solo.clickOnMenuItem("Add"); - solo.assertCurrentActivity("Expected CategoryEdit activity", "CategoryEdit"); - solo.enterText(0, "Category 1"); - solo.clickOnButton(0); - - solo.clickOnMenuItem("Add"); - solo.assertCurrentActivity("Expected CategoryEdit activity", "CategoryEdit"); - solo.enterText(0, "Category 2"); - solo.clickOnButton(0); - - boolean expected = true; - boolean actual = solo.searchText("Category 1") && solo.searchText("Category 2"); - assertEquals("Category 1 and/or Category 2 are not found", expected, actual); - } - - @Smoke - public void testCategoryEdit() throws Exception { + + solo.assertCurrentActivity("Expected CategoryList activity", "CategoryList"); + + solo.clickOnMenuItem("Add"); + solo.assertCurrentActivity("Expected CategoryEdit activity", "CategoryEdit"); + solo.enterText(0, "Category 1"); + solo.clickOnButton(0); + + solo.clickOnMenuItem("Add"); + solo.assertCurrentActivity("Expected CategoryEdit activity", "CategoryEdit"); + solo.enterText(0, "Category 2"); + solo.clickOnButton(0); + + boolean expected = true; + boolean actual = solo.searchText("Category 1") && solo.searchText("Category 2"); + assertEquals("Category 1 and/or Category 2 are not found", expected, actual); + } + + @Smoke + public void testCategoryEdit() throws Exception { // unlockIfNeeded(); - solo.clickLongOnText("Category 1"); + solo.clickLongOnText("Category 1"); // solo.setActivityOrientation(Solo.LANDSCAPE); // Change orientation of activity - solo.clickOnText("Edit"); // Change title - solo.enterText(0, " test"); //In first text field (0), add test. - solo.clickOnButton(0); + solo.clickOnText("Edit"); // Change title + solo.enterText(0, " test"); //In first text field (0), add test. + solo.clickOnButton(0); - boolean expected = true; - boolean actual = solo.searchText("Category 1 test"); // (Regexp) case insensitive - assertEquals("Note 1 test is not found", expected, actual); - } + boolean expected = true; + boolean actual = solo.searchText("Category 1 test"); // (Regexp) case insensitive + assertEquals("Note 1 test is not found", expected, actual); + } - - @Smoke - public void test_CategoryRemove() throws Exception { + @Smoke + public void test_CategoryRemove() throws Exception { // unlockIfNeeded(); - solo.clickLongOnText("Category 1.*"); - solo.clickOnText("Delete"); - boolean expected = false; - boolean actual = solo.searchText("Category 1 test"); - assertEquals("Category 1 Test is found", expected, actual); - solo.clickLongOnText("Category 2"); - solo.clickOnText("Delete"); - actual = solo.searchText("Category 2"); - assertEquals("Category 2 is found", expected, actual); - } - - @Smoke - public void testPasswordAdd() throws Exception { + solo.clickLongOnText("Category 1.*"); + solo.clickOnText("Delete"); + boolean expected = false; + boolean actual = solo.searchText("Category 1 test"); + assertEquals("Category 1 Test is found", expected, actual); + solo.clickLongOnText("Category 2"); + solo.clickOnText("Delete"); + actual = solo.searchText("Category 2"); + assertEquals("Category 2 is found", expected, actual); + } + + @Smoke + public void testPasswordAdd() throws Exception { // unlockIfNeeded(); - - solo.clickOnMenuItem("Add"); - solo.assertCurrentActivity("Expected CategoryEdit activity", "CategoryEdit"); - solo.enterText(0, "Category for Passwords"); - solo.clickOnButton(0); - - boolean expected = true; - boolean actual = solo.searchText("Category for Passwords"); - assertEquals("Category for Passwords are not found", expected, actual); - - solo.clickOnText("Category for Passwords"); - solo.assertCurrentActivity("Expected PassList activity", "PassList"); - - for (int i=1; i<4; i++) { - solo.clickOnMenuItem("Add"); - solo.assertCurrentActivity("Expected PassEdit activity", "PassEdit"); - - String entry="ptest"+i; - String entryDescription=entry+" description"; - solo.enterText(0, entryDescription); - solo.enterText(1, "http://www.google.com/"); - solo.enterText(2, entry+" user"); - solo.enterText(3, entry+" password"); - solo.enterText(4, entry+" note"); - solo.goBack(); - solo.assertCurrentActivity("Expected PassList activity", "PassList"); - - expected = true; - actual = solo.searchText(entryDescription); - assertEquals(entryDescription+"is not found", expected, actual); - } - } - - @Smoke - public void testPasswordEdit() throws Exception { - solo.clickOnText("Category for Passwords"); - solo.assertCurrentActivity("Expected PassList activity", "PassList"); - - solo.clickLongOnText("ptest1"); - solo.clickOnText("Edit"); - solo.assertCurrentActivity("Expected PassEdit activity", "PassEdit"); - - solo.enterText(0, " modified"); - solo.goBack(); - solo.assertCurrentActivity("Expected PassList activity", "PassList"); - - boolean expected = true; - boolean actual = solo.searchText("ptest1 description modified"); - assertEquals("edited password not found", expected, actual); + + solo.clickOnMenuItem("Add"); + solo.assertCurrentActivity("Expected CategoryEdit activity", "CategoryEdit"); + solo.enterText(0, "Category for Passwords"); + solo.clickOnButton(0); + + boolean expected = true; + boolean actual = solo.searchText("Category for Passwords"); + assertEquals("Category for Passwords are not found", expected, actual); + + solo.clickOnText("Category for Passwords"); + solo.assertCurrentActivity("Expected PassList activity", "PassList"); + + for (int i = 1; i < 4; i++) { + solo.clickOnMenuItem("Add"); + solo.assertCurrentActivity("Expected PassEdit activity", "PassEdit"); + + String entry = "ptest" + i; + String entryDescription = entry + " description"; + solo.enterText(0, entryDescription); + solo.enterText(1, "http://www.google.com/"); + solo.enterText(2, entry + " user"); + solo.enterText(3, entry + " password"); + solo.enterText(4, entry + " note"); + solo.goBack(); + solo.assertCurrentActivity("Expected PassList activity", "PassList"); + + expected = true; + actual = solo.searchText(entryDescription); + assertEquals(entryDescription + "is not found", expected, actual); + } + } + + @Smoke + public void testPasswordEdit() throws Exception { + solo.clickOnText("Category for Passwords"); + solo.assertCurrentActivity("Expected PassList activity", "PassList"); + + solo.clickLongOnText("ptest1"); + solo.clickOnText("Edit"); + solo.assertCurrentActivity("Expected PassEdit activity", "PassEdit"); + + solo.enterText(0, " modified"); + solo.goBack(); + solo.assertCurrentActivity("Expected PassList activity", "PassList"); + + boolean expected = true; + boolean actual = solo.searchText("ptest1 description modified"); + assertEquals("edited password not found", expected, actual); // solo.clickLongOnText("ptest2"); - solo.clickInList(2); - solo.assertCurrentActivity("Expected PassView activity", "PassView"); - - solo.clickOnMenuItem("Edit"); - solo.clickOnText("Edit"); - solo.assertCurrentActivity("Expected PassEdit activity", "PassEdit"); - - solo.enterText(0, " modified"); - solo.goBack(); - solo.goBack(); - solo.assertCurrentActivity("Expected PassList activity", "PassList"); - - expected = true; - actual = solo.searchText("ptest2 description modified"); - assertEquals("edited password2 not found", expected, actual); - - } - - @Smoke - public void testSearch() throws Exception { - // unlockIfNeeded(); - solo.clickOnMenuItem("Search"); - - solo.enterText(0, "ptest3"); - solo.clickOnButton("Search"); - solo.assertCurrentActivity("Expected Search activity", "Search"); - - solo.clickInList(1); - solo.assertCurrentActivity("Expected PassView activity", "PassView"); - - boolean expected = true; - boolean actual = solo.searchText("ptest3 description"); - assertEquals("description not found", expected, actual); - - solo.goBack(); - solo.assertCurrentActivity("Expected Search activity", "Search"); - - solo.setActivityOrientation(Solo.LANDSCAPE); - solo.clickInList(1); - solo.assertCurrentActivity("Expected PassView activity", "PassView"); - - expected = true; - actual = solo.searchText("ptest3 description"); - assertEquals("description not found", expected, actual); - - solo.setActivityOrientation(Solo.PORTRAIT); - } - - /** - * Remove all passwords present in test category - * - * @throws Exception - */ - @Smoke - public void test_PasswordRemove() throws Exception { - solo.clickOnText("Category for Passwords"); - solo.assertCurrentActivity("Expected PassList activity", "PassList"); - - while(solo.searchText("ptest")) { - solo.clickLongOnTextAndPress("ptest", 2); - solo.clickOnButton("Yes"); - } - boolean expected = true; - boolean actual = solo.searchText("No Passwords"); - assertEquals("Passwords still found", expected, actual); - } - - @Override - public void tearDown() throws Exception { - try { - solo.finishOpenedActivities(); - } catch (Throwable e) { - e.printStackTrace(); - } - getActivity().finish(); - super.tearDown(); - } + solo.clickInList(2); + solo.assertCurrentActivity("Expected PassView activity", "PassView"); + + solo.clickOnMenuItem("Edit"); + solo.clickOnText("Edit"); + solo.assertCurrentActivity("Expected PassEdit activity", "PassEdit"); + + solo.enterText(0, " modified"); + solo.goBack(); + solo.goBack(); + solo.assertCurrentActivity("Expected PassList activity", "PassList"); + + expected = true; + actual = solo.searchText("ptest2 description modified"); + assertEquals("edited password2 not found", expected, actual); + + } + + @Smoke + public void testSearch() throws Exception { + // unlockIfNeeded(); + solo.clickOnMenuItem("Search"); + + solo.enterText(0, "ptest3"); + solo.clickOnButton("Search"); + solo.assertCurrentActivity("Expected Search activity", "Search"); + + solo.clickInList(1); + solo.assertCurrentActivity("Expected PassView activity", "PassView"); + + boolean expected = true; + boolean actual = solo.searchText("ptest3 description"); + assertEquals("description not found", expected, actual); + + solo.goBack(); + solo.assertCurrentActivity("Expected Search activity", "Search"); + + solo.setActivityOrientation(Solo.LANDSCAPE); + solo.clickInList(1); + solo.assertCurrentActivity("Expected PassView activity", "PassView"); + + expected = true; + actual = solo.searchText("ptest3 description"); + assertEquals("description not found", expected, actual); + + solo.setActivityOrientation(Solo.PORTRAIT); + } + + /** + * Remove all passwords present in test category + * + * @throws Exception + */ + @Smoke + public void test_PasswordRemove() throws Exception { + solo.clickOnText("Category for Passwords"); + solo.assertCurrentActivity("Expected PassList activity", "PassList"); + + while (solo.searchText("ptest")) { + solo.clickLongOnTextAndPress("ptest", 2); + solo.clickOnButton("Yes"); + } + boolean expected = true; + boolean actual = solo.searchText("No Passwords"); + assertEquals("Passwords still found", expected, actual); + } + + @Override + public void tearDown() throws Exception { + try { + solo.finishOpenedActivities(); + } catch (Throwable e) { + e.printStackTrace(); + } + getActivity().finish(); + super.tearDown(); + } }