Merge remote-tracking branch 'development' into linked-identities

This commit is contained in:
Vincent Breitmoser
2015-03-10 00:57:23 +01:00
179 changed files with 1531 additions and 947 deletions

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg2"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="ic_action_encrypt_copy.svg">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2558"
inkscape:window-height="1419"
id="namedview6"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12.20339"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
d="M 14.129105,19.422026 H 6.8730841 v -9.234937 h 7.2560209 m 0,-1.3192761 H 6.8730841 A 1.3192767,1.3192767 0 0 0 5.5538069,10.187089 v 9.234937 a 1.3192767,1.3192767 0 0 0 1.3192772,1.319276 h 7.2560209 a 1.3192767,1.3192767 0 0 0 1.319278,-1.319276 V 10.187089 A 1.3192767,1.3192767 0 0 0 14.129105,8.8678129 M 12.150189,6.2292595 H 4.2345312 A 1.3192767,1.3192767 0 0 0 2.915254,7.5485361 V 16.783473 H 4.2345312 V 7.5485361 H 12.150189 V 6.2292595 z"
id="path4"
inkscape:connector-curvature="0" />
<path
id="path3076"
d="m 17.363197,9.8980016 a 0.84079901,0.84079901 0 0 0 0.840798,-0.8408 c 0,-0.466643 -0.378359,-0.840799 -0.840798,-0.840799 a 0.84079901,0.84079901 0 0 0 -0.8408,0.840799 0.84079901,0.84079901 0 0 0 0.8408,0.8408 m 2.522396,-3.783596 a 0.84079901,0.84079901 0 0 1 0.8408,0.840799 V 11.159199 A 0.84079901,0.84079901 0 0 1 19.885593,12 H 14.840799 A 0.84079901,0.84079901 0 0 1 14,11.159199 V 6.9552046 c 0,-0.466644 0.37836,-0.840799 0.840799,-0.840799 h 0.4204 v -0.840799 a 2.1019975,2.1019975 0 0 1 2.101998,-2.101997 2.1019975,2.1019975 0 0 1 2.101997,2.101997 v 0.840799 h 0.420399 m -2.522396,-2.101998 a 1.2611986,1.2611986 0 0 0 -1.261198,1.261199 v 0.840799 h 2.522396 v -0.840799 a 1.2611986,1.2611986 0 0 0 -1.261198,-1.261199 z"
inkscape:connector-curvature="0"
style="fill:#000000" />
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg2"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="ic_action_encrypt_save.svg">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2558"
inkscape:window-height="1419"
id="namedview6"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12.20339"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
inkscape:connector-curvature="0"
d="M 12.355932,11.847458 H 4.7288135 V 8.7966102 H 12.355932 M 10.067797,19.474576 a 2.2881356,2.2881356 0 0 1 -2.288136,-2.288135 2.2881356,2.2881356 0 0 1 2.288136,-2.288136 2.2881356,2.2881356 0 0 1 2.288135,2.288136 2.2881356,2.2881356 0 0 1 -2.288135,2.288135 M 13.881356,7.2711864 H 4.7288135 c -0.8466101,0 -1.5254237,0.6864407 -1.5254237,1.5254238 V 19.474576 A 1.5254237,1.5254237 0 0 0 4.7288135,21 H 15.40678 a 1.5254237,1.5254237 0 0 0 1.525424,-1.525424 V 10.322034 L 13.881356,7.2711864 z"
id="path4-7" />
<path
id="path3076-1"
d="m 17.363197,9.8980016 a 0.84079901,0.84079901 0 0 0 0.840798,-0.8408 c 0,-0.466643 -0.378359,-0.840799 -0.840798,-0.840799 a 0.84079901,0.84079901 0 0 0 -0.8408,0.840799 0.84079901,0.84079901 0 0 0 0.8408,0.8408 m 2.522396,-3.783596 a 0.84079901,0.84079901 0 0 1 0.8408,0.840799 V 11.159199 A 0.84079901,0.84079901 0 0 1 19.885593,12 H 14.840799 A 0.84079901,0.84079901 0 0 1 14,11.159199 V 6.9552046 c 0,-0.466644 0.37836,-0.840799 0.840799,-0.840799 h 0.4204 v -0.840799 a 2.1019975,2.1019975 0 0 1 2.101998,-2.101997 2.1019975,2.1019975 0 0 1 2.101997,2.101997 v 0.840799 h 0.420399 m -2.522396,-2.101998 a 1.2611986,1.2611986 0 0 0 -1.261198,1.261199 v 0.840799 h 2.522396 v -0.840799 a 1.2611986,1.2611986 0 0 0 -1.261198,-1.261199 z"
inkscape:connector-curvature="0"
style="fill:#000000" />
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg2"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="ic_action_encrypt_share.svg">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2558"
inkscape:window-height="1419"
id="namedview6"
showgrid="false"
inkscape:zoom="13.906433"
inkscape:cx="16.307191"
inkscape:cy="17.104487"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
inkscape:connector-curvature="0"
d="m 13.957374,17.775285 c -0.544868,0 -1.032382,0.215079 -1.405187,0.552038 L 7.4404597,15.352054 c 0.035847,-0.164895 0.064524,-0.329789 0.064524,-0.501853 0,-0.172063 -0.028677,-0.336958 -0.064524,-0.501852 l 5.0543733,-2.946592 c 0.387142,0.358465 0.896165,0.580715 1.462541,0.580715 a 2.1507969,2.1507969 0 0 0 2.150798,-2.1507972 2.1507969,2.1507969 0 0 0 -2.150798,-2.150797 2.1507969,2.1507969 0 0 0 -2.150796,2.150797 c 0,0.1720642 0.02868,0.3369582 0.06452,0.5018532 l -5.0543685,2.94659 C 6.4295852,12.921653 5.9205632,12.699404 5.3541867,12.699404 a 2.1507969,2.1507969 0 0 0 -2.1507969,2.150797 2.1507969,2.1507969 0 0 0 2.1507969,2.150796 c 0.5663765,0 1.0753985,-0.222248 1.4625419,-0.580715 l 5.1045584,2.975269 c -0.03585,0.150556 -0.05735,0.308281 -0.05735,0.473176 0,1.154261 0.939182,2.086273 2.093442,2.086273 1.154262,0 2.093443,-0.932012 2.093443,-2.086273 a 2.0934423,2.0934423 0 0 0 -2.093443,-2.093442 z"
id="path4-9" />
<path
id="path3076-1"
d="m 17.363197,9.898002 a 0.84079901,0.84079901 0 0 0 0.840798,-0.8408 c 0,-0.466643 -0.378359,-0.840799 -0.840798,-0.840799 a 0.84079901,0.84079901 0 0 0 -0.8408,0.840799 0.84079901,0.84079901 0 0 0 0.8408,0.8408 m 2.522396,-3.783596 a 0.84079901,0.84079901 0 0 1 0.8408,0.840799 v 4.203994 A 0.84079901,0.84079901 0 0 1 19.885593,12 H 14.840799 A 0.84079901,0.84079901 0 0 1 14,11.159199 V 6.955205 c 0,-0.466644 0.37836,-0.840799 0.840799,-0.840799 h 0.4204 V 5.2736068 a 2.1019975,2.1019975 0 0 1 2.101998,-2.101997 2.1019975,2.1019975 0 0 1 2.101997,2.101997 V 6.114406 h 0.420399 M 17.363197,4.0124078 a 1.2611986,1.2611986 0 0 0 -1.261198,1.261199 V 6.114406 h 2.522396 V 5.2736068 a 1.2611986,1.2611986 0 0 0 -1.261198,-1.261199 z"
inkscape:connector-curvature="0"
style="fill:#000000" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,8 @@
<!-- drawable/comment-text.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M9,22A1,1 0 0,1 8,21V18H4A2,2 0 0,1 2,16V4C2,2.89 2.9,2 4,2H20A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H13.9L10.2,21.71C10,21.9 9.75,22 9.5,22V22H9M5,5V7H19V5H5M5,9V11H13V9H5M5,13V15H15V13H5Z" />
</vector>

View File

@@ -0,0 +1,5 @@
Thanks for visiting MaterialDesignIcons.com
Check back often for new icons and follow @MaterialIcons for updates.
Icon: comment-text
By: Austin Andrews

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" /></svg>

After

Width:  |  Height:  |  Size: 417 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z" /></svg>

After

Width:  |  Height:  |  Size: 445 B

View File

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 253 B

View File

Before

Width:  |  Height:  |  Size: 335 B

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M18,16.08C17.24,16.08 16.56,16.38 16.04,16.85L8.91,12.7C8.96,12.47 9,12.24 9,12C9,11.76 8.96,11.53 8.91,11.3L15.96,7.19C16.5,7.69 17.21,8 18,8A3,3 0 0,0 21,5A3,3 0 0,0 18,2A3,3 0 0,0 15,5C15,5.24 15.04,5.47 15.09,5.7L8.04,9.81C7.5,9.31 6.79,9 6,9A3,3 0 0,0 3,12A3,3 0 0,0 6,15C6.79,15 7.5,14.69 8.04,14.19L15.16,18.34C15.11,18.55 15.08,18.77 15.08,19C15.08,20.61 16.39,21.91 18,21.91C19.61,21.91 20.92,20.61 20.92,19A2.92,2.92 0 0,0 18,16.08Z" /></svg>

After

Width:  |  Height:  |  Size: 737 B

View File

@@ -11,6 +11,7 @@ python copy OpenKeychain av white repeat 24
python copy OpenKeychain av grey repeat 24 python copy OpenKeychain av grey repeat 24
python copy OpenKeychain editor white mode_edit 24 python copy OpenKeychain editor white mode_edit 24
python copy OpenKeychain content white save 24 python copy OpenKeychain content white save 24
python copy OpenKeychain navigation black close 24
python copy OpenKeychain action grey delete 24 python copy OpenKeychain action grey delete 24
python copy OpenKeychain action grey done 24 python copy OpenKeychain action grey done 24
@@ -36,6 +37,9 @@ python copy OpenKeychain social grey person 24
python copy OpenKeychain social grey person_add 24 python copy OpenKeychain social grey person_add 24
python copy OpenKeychain social grey share 24 python copy OpenKeychain social grey share 24
python copy OpenKeychain communication grey vpn_key 24 python copy OpenKeychain communication grey vpn_key 24
python copy OpenKeychain navigation grey chevron_left 24
python copy OpenKeychain navigation grey chevron_right 24
python copy OpenKeychain social grey person 48
# navigation drawer sections # navigation drawer sections
python copy OpenKeychain communication black vpn_key 24 python copy OpenKeychain communication black vpn_key 24

View File

@@ -22,7 +22,7 @@ SRC_DIR=./drawables/
#inkscape -w 512 -h 512 -e "$PLAY_DIR/$NAME.png" $NAME.svg #inkscape -w 512 -h 512 -e "$PLAY_DIR/$NAME.png" $NAME.svg
for NAME in "ic_cloud_search" "ic_action_encrypt_file" "ic_action_encrypt_text" "ic_action_verified_cutout" "status_lock_closed" "status_lock_error" "status_lock_open" "status_signature_expired_cutout" "status_signature_invalid_cutout" "status_signature_revoked_cutout" "status_signature_unknown_cutout" "status_signature_unverified_cutout" "status_signature_verified_cutout" "key_flag_authenticate" "key_flag_certify" "key_flag_encrypt" "key_flag_sign" for NAME in "ic_cloud_search" "ic_action_encrypt_file" "ic_action_encrypt_text" "ic_action_verified_cutout" "ic_action_encrypt_copy" "ic_action_encrypt_save" "ic_action_encrypt_share" "status_lock_closed" "status_lock_error" "status_lock_open" "status_signature_expired_cutout" "status_signature_invalid_cutout" "status_signature_revoked_cutout" "status_signature_unknown_cutout" "status_signature_unverified_cutout" "status_signature_verified_cutout" "key_flag_authenticate" "key_flag_certify" "key_flag_encrypt" "key_flag_sign"
do do
echo $NAME echo $NAME
inkscape -w 24 -h 24 -e "$MDPI_DIR/${NAME}_24dp.png" "$SRC_DIR/$NAME.svg" inkscape -w 24 -h 24 -e "$MDPI_DIR/${NAME}_24dp.png" "$SRC_DIR/$NAME.svg"

View File

@@ -93,7 +93,7 @@
<activity <activity
android:name=".ui.CreateKeyActivity" android:name=".ui.CreateKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard" android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:windowSoftInputMode="stateHidden|adjustResize" android:windowSoftInputMode="adjustResize"
android:label="@string/title_create_key" android:label="@string/title_create_key"
android:parentActivityName=".ui.MainActivity"> android:parentActivityName=".ui.MainActivity">
<meta-data <meta-data

View File

@@ -38,8 +38,6 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEnt
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
import org.sufficientlysecure.keychain.pgp.PgpConstants; import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInput; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInput;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@@ -55,7 +53,6 @@ import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Preferences;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -83,7 +80,7 @@ public class OpenPgpService extends RemoteService {
* @param encryptionUserIds * @param encryptionUserIds
* @return * @return
*/ */
private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) { private Intent returnKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0); boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0);
boolean missingUserIdsCheck = false; boolean missingUserIdsCheck = false;
boolean duplicateUserIdsCheck = false; boolean duplicateUserIdsCheck = false;
@@ -164,50 +161,7 @@ public class OpenPgpService extends RemoteService {
} }
} }
private Intent getNfcSignIntent(Intent data, long keyId, String pin, byte[] hashToSign, int hashAlgo) { private Intent returnPassphraseIntent(Intent data, long keyId) {
// build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_SIGN_HASH);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(NfcActivity.EXTRA_DATA, data);
intent.putExtra(NfcActivity.EXTRA_PIN, pin);
intent.putExtra(NfcActivity.EXTRA_KEY_ID, keyId);
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign);
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
// return PendingIntent to be executed by client
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result;
}
private Intent getNfcDecryptIntent(Intent data, long subKeyId, String pin, byte[] encryptedSessionKey) {
// build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(NfcActivity.EXTRA_DATA, data);
intent.putExtra(NfcActivity.EXTRA_PIN, pin);
intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId);
intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
// return PendingIntent to be executed by client
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result;
}
private Intent getPassphraseIntent(Intent data, long keyId) {
// build PendingIntent for passphrase input // build PendingIntent for passphrase input
Intent intent = new Intent(getBaseContext(), PassphraseDialogActivity.class); Intent intent = new Intent(getBaseContext(), PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, keyId); intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, keyId);
@@ -224,6 +178,59 @@ public class OpenPgpService extends RemoteService {
return result; return result;
} }
private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, String pin, byte[] hashToSign, int hashAlgo) {
// build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_SIGN_HASH);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(NfcActivity.EXTRA_DATA, data);
intent.putExtra(NfcActivity.EXTRA_PIN, pin);
intent.putExtra(NfcActivity.EXTRA_KEY_ID, keyId);
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign);
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo);
return PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, String pin, byte[] encryptedSessionKey) {
// build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(NfcActivity.EXTRA_DATA, data);
intent.putExtra(NfcActivity.EXTRA_PIN, pin);
intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId);
intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey);
return PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
private PendingIntent getKeyserverPendingIntent(Intent data, long masterKeyId) {
// If signature is unknown we return an _additional_ PendingIntent
// to retrieve the missing key
Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class);
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE);
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, masterKeyId);
intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
return PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
private PendingIntent getShowKeyPendingIntent(long masterKeyId) {
Intent intent = new Intent(getBaseContext(), ViewKeyActivity.class);
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
return PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
private Intent signImpl(Intent data, ParcelFileDescriptor input, private Intent signImpl(Intent data, ParcelFileDescriptor input,
ParcelFileDescriptor output, AccountSettings accSettings, ParcelFileDescriptor output, AccountSettings accSettings,
boolean cleartextSign) { boolean cleartextSign) {
@@ -274,21 +281,27 @@ public class OpenPgpService extends RemoteService {
if (pgpResult.isPending()) { if (pgpResult.isPending()) {
if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) {
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); return returnPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
} else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) ==
PgpSignEncryptResult.RESULT_PENDING_NFC) { PgpSignEncryptResult.RESULT_PENDING_NFC) {
// return PendingIntent to execute NFC activity // return PendingIntent to execute NFC activity
// pass through the signature creation timestamp to be used again on second execution // pass through the signature creation timestamp to be used again on second execution
// of PgpSignEncrypt when we have the signed hash! // of PgpSignEncrypt when we have the signed hash!
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
// return PendingIntent to be executed by client
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_INTENT,
getNfcSignPendingIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result;
} else { } else {
throw new PgpGeneralException( throw new PgpGeneralException(
"Encountered unhandled type of pending action not supported by API!"); "Encountered unhandled type of pending action not supported by API!");
} }
} else if (pgpResult.success()) { } else if (pgpResult.success()) {
Intent result = new Intent(); Intent result = new Intent();
if (!cleartextSign) { if (pgpResult.getDetachedSignature() != null && !cleartextSign) {
result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature()); result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature());
} }
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
@@ -340,7 +353,7 @@ public class OpenPgpService extends RemoteService {
// get key ids based on given user ids // get key ids based on given user ids
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
// give params through to activity... // give params through to activity...
Intent result = getKeyIdsFromEmails(data, userIds); Intent result = returnKeyIdsFromEmails(data, userIds);
if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) { if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) {
keyIds = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS); keyIds = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS);
@@ -391,14 +404,19 @@ public class OpenPgpService extends RemoteService {
if (pgpResult.isPending()) { if (pgpResult.isPending()) {
if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) {
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); return returnPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
} else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) ==
PgpSignEncryptResult.RESULT_PENDING_NFC) { PgpSignEncryptResult.RESULT_PENDING_NFC) {
// return PendingIntent to execute NFC activity // return PendingIntent to execute NFC activity
// pass through the signature creation timestamp to be used again on second execution // pass through the signature creation timestamp to be used again on second execution
// of PgpSignEncrypt when we have the signed hash! // of PgpSignEncrypt when we have the signed hash!
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); // return PendingIntent to be executed by client
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_INTENT,
getNfcSignPendingIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result;
} else { } else {
throw new PgpGeneralException( throw new PgpGeneralException(
"Encountered unhandled type of pending action not supported by API!"); "Encountered unhandled type of pending action not supported by API!");
@@ -478,15 +496,20 @@ public class OpenPgpService extends RemoteService {
if (pgpResult.isPending()) { if (pgpResult.isPending()) {
if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); return returnPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
throw new PgpGeneralException( throw new PgpGeneralException(
"Decryption of symmetric content not supported by API!"); "Decryption of symmetric content not supported by API!");
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
DecryptVerifyResult.RESULT_PENDING_NFC) { DecryptVerifyResult.RESULT_PENDING_NFC) {
return getNfcDecryptIntent(
data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); // return PendingIntent to be executed by client
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_INTENT,
getNfcDecryptPendingIntent(data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result;
} else { } else {
throw new PgpGeneralException( throw new PgpGeneralException(
"Encountered unhandled type of pending action not supported by API!"); "Encountered unhandled type of pending action not supported by API!");
@@ -509,16 +532,10 @@ public class OpenPgpService extends RemoteService {
if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) { if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) {
// If signature is unknown we return an _additional_ PendingIntent // If signature is unknown we return an _additional_ PendingIntent
// to retrieve the missing key // to retrieve the missing key
Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); result.putExtra(OpenPgpApi.RESULT_INTENT, getKeyserverPendingIntent(data, signatureResult.getKeyId()));
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE); } else {
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId()); // If signature key is known, return PendingIntent to show key
intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); result.putExtra(OpenPgpApi.RESULT_INTENT, getShowKeyPendingIntent(signatureResult.getKeyId()));
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
} }
} }
@@ -576,33 +593,15 @@ public class OpenPgpService extends RemoteService {
Intent result = new Intent(); Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
// also return PendingIntent that opens the key view activity // also return PendingIntent that opens the key view activity
Intent intent = new Intent(getBaseContext(), ViewKeyActivity.class); result.putExtra(OpenPgpApi.RESULT_INTENT, getShowKeyPendingIntent(masterKeyId));
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
return result; return result;
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
Intent result = new Intent();
// If keys are not in db we return an additional PendingIntent // If keys are not in db we return an additional PendingIntent
// to retrieve the missing key // to retrieve the missing key
Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); Intent result = new Intent();
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE); result.putExtra(OpenPgpApi.RESULT_INTENT, getKeyserverPendingIntent(data, masterKeyId));
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, masterKeyId);
intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
return result; return result;
} }
@@ -629,7 +628,7 @@ public class OpenPgpService extends RemoteService {
} else { } else {
// get key ids based on given user ids // get key ids based on given user ids
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
return getKeyIdsFromEmails(data, userIds); return returnKeyIdsFromEmails(data, userIds);
} }
} }
@@ -669,7 +668,7 @@ public class OpenPgpService extends RemoteService {
return result; return result;
} }
// check if caller is allowed to access openpgp keychain // check if caller is allowed to access OpenKeychain
Intent result = isAllowed(data); Intent result = isAllowed(data);
if (result != null) { if (result != null) {
return result; return result;

View File

@@ -88,12 +88,20 @@ public abstract class BaseActivity extends ActionBarActivity {
/** /**
* Close button only * Close button only
*/ */
protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener) { protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener, boolean white) {
setActionBarIcon(R.drawable.ic_close_white_24dp); if (white) {
setActionBarIcon(R.drawable.ic_close_white_24dp);
} else {
setActionBarIcon(R.drawable.ic_close_black_24dp);
}
getSupportActionBar().setDisplayShowTitleEnabled(true); getSupportActionBar().setDisplayShowTitleEnabled(true);
mToolbar.setNavigationOnClickListener(cancelOnClickListener); mToolbar.setNavigationOnClickListener(cancelOnClickListener);
} }
protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener) {
setFullScreenDialogClose(cancelOnClickListener, true);
}
/** /**
* Inflate custom design with two buttons using drawables. * Inflate custom design with two buttons using drawables.
* This does not conform to the Material Design Guidelines, but we deviate here as this is used * This does not conform to the Material Design Guidelines, but we deviate here as this is used

View File

@@ -39,8 +39,8 @@ public class CreateKeyActivity extends BaseActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// pass extras into fragment // pass extras into fragment
CreateKeyInputFragment frag = CreateKeyNameFragment frag =
CreateKeyInputFragment.newInstance( CreateKeyNameFragment.newInstance(
getIntent().getStringExtra(EXTRA_NAME), getIntent().getStringExtra(EXTRA_NAME),
getIntent().getStringExtra(EXTRA_EMAIL) getIntent().getStringExtra(EXTRA_EMAIL)
); );

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
public class CreateKeyEmailFragment extends Fragment {
public static final String ARG_NAME = "name";
public static final String ARG_EMAIL = "email";
CreateKeyActivity mCreateKeyActivity;
EmailEditText mEmailEdit;
View mBackButton;
View mNextButton;
String mName;
/**
* Creates new instance of this fragment
*/
public static CreateKeyEmailFragment newInstance(String name, String email) {
CreateKeyEmailFragment frag = new CreateKeyEmailFragment();
Bundle args = new Bundle();
args.putString(ARG_NAME, name);
args.putString(ARG_EMAIL, email);
frag.setArguments(args);
return frag;
}
/**
* Checks if text of given EditText is not empty. If it is empty an error is
* set and the EditText gets the focus.
*
* @param context
* @param editText
* @return true if EditText is not empty
*/
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
boolean output = true;
if (editText.getText().toString().length() == 0) {
editText.setError(context.getString(R.string.create_key_empty));
editText.requestFocus();
output = false;
} else {
editText.setError(null);
}
return output;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_key_email_fragment, container, false);
mEmailEdit = (EmailEditText) view.findViewById(R.id.create_key_email);
mBackButton = view.findViewById(R.id.create_key_back_button);
mNextButton = view.findViewById(R.id.create_key_next_button);
// initial values
mName = getArguments().getString(ARG_NAME);
String email = getArguments().getString(ARG_EMAIL);
mEmailEdit.setText(email);
// focus empty edit fields
if (email == null) {
mEmailEdit.requestFocus();
}
mBackButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT);
}
});
mNextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createKeyCheck();
}
});
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCreateKeyActivity = (CreateKeyActivity) getActivity();
}
private void createKeyCheck() {
if (isEditTextNotEmpty(getActivity(), mEmailEdit)) {
CreateKeyPassphraseFragment frag =
CreateKeyPassphraseFragment.newInstance(
mName,
mEmailEdit.getText().toString()
);
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
}
}
}

View File

@@ -95,7 +95,7 @@ public class CreateKeyFinalFragment extends Fragment {
mEmailEdit = (TextView) view.findViewById(R.id.email); mEmailEdit = (TextView) view.findViewById(R.id.email);
mUploadCheckbox = (CheckBox) view.findViewById(R.id.create_key_upload); mUploadCheckbox = (CheckBox) view.findViewById(R.id.create_key_upload);
mBackButton = view.findViewById(R.id.create_key_back_button); mBackButton = view.findViewById(R.id.create_key_back_button);
mCreateButton = view.findViewById(R.id.create_key_create_button); mCreateButton = view.findViewById(R.id.create_key_next_button);
mEditText = (TextView) view.findViewById(R.id.create_key_edit_text); mEditText = (TextView) view.findViewById(R.id.create_key_edit_text);
mEditButton = view.findViewById(R.id.create_key_edit_button); mEditButton = view.findViewById(R.id.create_key_edit_button);

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
import org.sufficientlysecure.keychain.ui.widget.NameEditText;
public class CreateKeyNameFragment extends Fragment {
public static final String ARG_NAME = "name";
public static final String ARG_EMAIL = "email";
CreateKeyActivity mCreateKeyActivity;
NameEditText mNameEdit;
View mNextButton;
String mEmail;
/**
* Creates new instance of this fragment
*/
public static CreateKeyNameFragment newInstance(String name, String email) {
CreateKeyNameFragment frag = new CreateKeyNameFragment();
Bundle args = new Bundle();
args.putString(ARG_NAME, name);
args.putString(ARG_EMAIL, email);
frag.setArguments(args);
return frag;
}
/**
* Checks if text of given EditText is not empty. If it is empty an error is
* set and the EditText gets the focus.
*
* @param context
* @param editText
* @return true if EditText is not empty
*/
private static boolean isEditTextNotEmpty(Context context, EditText editText) {
boolean output = true;
if (editText.getText().toString().length() == 0) {
editText.setError(context.getString(R.string.create_key_empty));
editText.requestFocus();
output = false;
} else {
editText.setError(null);
}
return output;
}
private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
boolean output = true;
if (!editText1.getText().toString().equals(editText2.getText().toString())) {
editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
editText2.requestFocus();
output = false;
} else {
editText2.setError(null);
}
return output;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_key_name_fragment, container, false);
mNameEdit = (NameEditText) view.findViewById(R.id.create_key_name);
mNextButton = view.findViewById(R.id.create_key_next_button);
// initial values
String name = getArguments().getString(ARG_NAME);
mEmail = getArguments().getString(ARG_EMAIL);
mNameEdit.setText(name);
// focus empty edit fields
if (name == null) {
mNameEdit.requestFocus();
}
mNextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createKeyCheck();
}
});
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCreateKeyActivity = (CreateKeyActivity) getActivity();
}
private void createKeyCheck() {
if (isEditTextNotEmpty(getActivity(), mNameEdit)) {
CreateKeyEmailFragment frag =
CreateKeyEmailFragment.newInstance(
mNameEdit.getText().toString(),
mEmail
);
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
}
}
}

View File

@@ -17,43 +17,46 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter; import android.widget.CheckBox;
import android.widget.AutoCompleteTextView; import android.widget.CompoundButton;
import android.widget.EditText; import android.widget.EditText;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.widget.EmailEditText; import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
import org.sufficientlysecure.keychain.ui.widget.PasswordEditText;
import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthView;
import org.sufficientlysecure.keychain.util.ContactHelper;
public class CreateKeyInputFragment extends Fragment { public class CreateKeyPassphraseFragment extends Fragment {
CreateKeyActivity mCreateKeyActivity;
PasswordStrengthView mPassphraseStrengthView;
AutoCompleteTextView mNameEdit;
EmailEditText mEmailEdit;
PasswordEditText mPassphraseEdit;
EditText mPassphraseEditAgain;
View mCreateButton;
public static final String ARG_NAME = "name"; public static final String ARG_NAME = "name";
public static final String ARG_EMAIL = "email"; public static final String ARG_EMAIL = "email";
// model
String mName;
String mEmail;
// view
CreateKeyActivity mCreateKeyActivity;
PassphraseEditText mPassphraseEdit;
EditText mPassphraseEditAgain;
CheckBox mShowPassphrase;
View mBackButton;
View mNextButton;
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
*/ */
public static CreateKeyInputFragment newInstance(String name, String email) { public static CreateKeyPassphraseFragment newInstance(String name, String email) {
CreateKeyInputFragment frag = new CreateKeyInputFragment(); CreateKeyPassphraseFragment frag = new CreateKeyPassphraseFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(ARG_NAME, name); args.putString(ARG_NAME, name);
@@ -64,107 +67,6 @@ public class CreateKeyInputFragment extends Fragment {
return frag; return frag;
} }
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_key_input_fragment, container, false);
mPassphraseStrengthView = (PasswordStrengthView) view.findViewById(R.id
.create_key_passphrase_strength);
mNameEdit = (AutoCompleteTextView) view.findViewById(R.id.create_key_name);
mEmailEdit = (EmailEditText) view.findViewById(R.id.create_key_email);
mPassphraseEdit = (PasswordEditText) view.findViewById(R.id.create_key_passphrase);
mPassphraseEditAgain = (EditText) view.findViewById(R.id.create_key_passphrase_again);
mCreateButton = view.findViewById(R.id.create_key_button);
// initial values
String name = getArguments().getString(ARG_NAME);
String email = getArguments().getString(ARG_EMAIL);
mNameEdit.setText(name);
mEmailEdit.setText(email);
// focus non-empty edit fields
if (name != null && email != null) {
mPassphraseEdit.requestFocus();
} else if (name != null) {
mEmailEdit.requestFocus();
}
mEmailEdit.setThreshold(1); // Start working from first character
mEmailEdit.setAdapter(
new ArrayAdapter<>
(getActivity(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserEmails(getActivity())
)
);
mNameEdit.setThreshold(1); // Start working from first character
mNameEdit.setAdapter(
new ArrayAdapter<>
(getActivity(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserNames(getActivity())
)
);
// Edit text padding doesn't work via xml (http://code.google.com/p/android/issues/detail?id=77982)
// so we set the right padding programmatically.
mPassphraseEdit.setPadding(mPassphraseEdit.getPaddingLeft(),
mPassphraseEdit.getPaddingTop(),
(int) (56 * getResources().getDisplayMetrics().density),
mPassphraseEdit.getPaddingBottom());
mPassphraseEdit.setPasswordStrengthView(mPassphraseStrengthView);
mCreateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createKeyCheck();
}
});
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mCreateKeyActivity = (CreateKeyActivity) getActivity();
}
private void createKeyCheck() {
if (isEditTextNotEmpty(getActivity(), mNameEdit)
&& isEditTextNotEmpty(getActivity(), mEmailEdit)
&& isEditTextNotEmpty(getActivity(), mPassphraseEdit)
&& areEditTextsEqual(getActivity(), mPassphraseEdit, mPassphraseEditAgain)) {
CreateKeyFinalFragment frag =
CreateKeyFinalFragment.newInstance(
mNameEdit.getText().toString(),
mEmailEdit.getText().toString(),
mPassphraseEdit.getText().toString()
);
hideKeyboard();
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
}
}
private void hideKeyboard() {
if (getActivity() == null) {
return;
}
InputMethodManager inputManager = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
// check if no view has focus
View v = getActivity().getCurrentFocus();
if (v == null)
return;
inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
/** /**
* Checks if text of given EditText is not empty. If it is empty an error is * Checks if text of given EditText is not empty. If it is empty an error is
* set and the EditText gets the focus. * set and the EditText gets the focus.
@@ -199,4 +101,89 @@ public class CreateKeyInputFragment extends Fragment {
return output; return output;
} }
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_key_passphrase_fragment, container, false);
mPassphraseEdit = (PassphraseEditText) view.findViewById(R.id.create_key_passphrase);
mPassphraseEditAgain = (EditText) view.findViewById(R.id.create_key_passphrase_again);
mShowPassphrase = (CheckBox) view.findViewById(R.id.create_key_show_passphrase);
mBackButton = view.findViewById(R.id.create_key_back_button);
mNextButton = view.findViewById(R.id.create_key_next_button);
// initial values
mName = getArguments().getString(ARG_NAME);
mEmail = getArguments().getString(ARG_EMAIL);
mPassphraseEdit.requestFocus();
mBackButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
back();
}
});
mNextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createKeyCheck();
}
});
mShowPassphrase.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
mPassphraseEdit.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
mPassphraseEditAgain.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
} else {
mPassphraseEdit.setTransformationMethod(PasswordTransformationMethod.getInstance());
mPassphraseEditAgain.setTransformationMethod(PasswordTransformationMethod.getInstance());
}
}
});
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCreateKeyActivity = (CreateKeyActivity) getActivity();
}
private void back() {
hideKeyboard();
mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT);
}
private void createKeyCheck() {
if (isEditTextNotEmpty(getActivity(), mPassphraseEdit)
&& areEditTextsEqual(getActivity(), mPassphraseEdit, mPassphraseEditAgain)) {
CreateKeyFinalFragment frag =
CreateKeyFinalFragment.newInstance(
mName,
mEmail,
mPassphraseEdit.getText().toString()
);
hideKeyboard();
mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT);
}
}
private void hideKeyboard() {
if (getActivity() == null) {
return;
}
InputMethodManager inputManager = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
// check if no view has focus
View v = getActivity().getCurrentFocus();
if (v == null)
return;
inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
} }

View File

@@ -17,9 +17,12 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.View;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@@ -40,6 +43,14 @@ public class DecryptFilesActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setFullScreenDialogClose(new View.OnClickListener() {
@Override
public void onClick(View v) {
setResult(Activity.RESULT_CANCELED);
finish();
}
}, false);
// Handle intent actions // Handle intent actions
handleActions(savedInstanceState, getIntent()); handleActions(savedInstanceState, getIntent());
} }

View File

@@ -18,9 +18,11 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@@ -49,6 +51,14 @@ public class DecryptTextActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setFullScreenDialogClose(new View.OnClickListener() {
@Override
public void onClick(View v) {
setResult(Activity.RESULT_CANCELED);
finish();
}
}, false);
// Handle intent actions // Handle intent actions
handleActions(savedInstanceState, getIntent()); handleActions(savedInstanceState, getIntent());
} }

View File

@@ -1,10 +1,29 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.view.View;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@@ -26,6 +45,19 @@ public abstract class EncryptActivity extends BaseActivity {
protected Date mNfcTimestamp = null; protected Date mNfcTimestamp = null;
protected byte[] mNfcHash = null; protected byte[] mNfcHash = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setFullScreenDialogClose(new View.OnClickListener() {
@Override
public void onClick(View v) {
setResult(Activity.RESULT_CANCELED);
finish();
}
}, false);
}
protected void startPassphraseDialog(long subkeyId) { protected void startPassphraseDialog(long subkeyId) {
Intent intent = new Intent(this, PassphraseDialogActivity.class); Intent intent = new Intent(this, PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId);

View File

@@ -67,8 +67,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
private String mEncryptionUserIds[] = null; private String mEncryptionUserIds[] = null;
private long mSigningKeyId = Constants.key.none; private long mSigningKeyId = Constants.key.none;
private String mPassphrase = ""; private String mPassphrase = "";
private boolean mUseArmor; private boolean mUseArmor = false;
private boolean mUseCompression; private boolean mUseCompression = true;
private boolean mDeleteAfterEncrypt = false; private boolean mDeleteAfterEncrypt = false;
private boolean mShareAfterEncrypt = false; private boolean mShareAfterEncrypt = false;
private ArrayList<Uri> mInputUris; private ArrayList<Uri> mInputUris;
@@ -209,6 +209,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
} else { } else {
data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED);
} }
data.setEnableAsciiArmorOutput(mUseArmor);
data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED);
@@ -314,15 +315,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// if called with an intent action, do not init drawer navigation
if (ACTION_ENCRYPT_DATA.equals(getIntent().getAction())) {
// lock drawer
// deactivateDrawerNavigation();
// TODO: back button to key?
} else {
// activateDrawerNavigation(savedInstanceState);
}
// Handle intent actions // Handle intent actions
handleActions(getIntent()); handleActions(getIntent());
updateModeFragment(); updateModeFragment();
@@ -339,17 +331,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
private void updateModeFragment() {
getSupportFragmentManager().beginTransaction()
.replace(R.id.encrypt_pager_mode,
mCurrentMode == MODE_SYMMETRIC
? new EncryptSymmetricFragment()
: new EncryptAsymmetricFragment()
)
.commitAllowingStateLoss();
getSupportFragmentManager().executePendingTransactions();
}
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.isCheckable()) { if (item.isCheckable()) {
@@ -384,6 +365,17 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
return true; return true;
} }
private void updateModeFragment() {
getSupportFragmentManager().beginTransaction()
.replace(R.id.encrypt_pager_mode,
mCurrentMode == MODE_SYMMETRIC
? new EncryptSymmetricFragment()
: new EncryptAsymmetricFragment()
)
.commitAllowingStateLoss();
getSupportFragmentManager().executePendingTransactions();
}
/** /**
* Handles all actions with this intent * Handles all actions with this intent
* *
@@ -418,9 +410,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
} }
if (extras.containsKey(EXTRA_ASCII_ARMOR)) { mUseArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, false);
mUseArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, true);
}
// preselect keys given by intent // preselect keys given by intent
mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID);
@@ -428,7 +418,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
// Save uris // Save uris
mInputUris = uris; mInputUris = uris;
} }
} }

View File

@@ -27,6 +27,7 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
@@ -56,7 +57,6 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt
// view // view
private View mAddView; private View mAddView;
private View mShareFile;
private ListView mSelectedFiles; private ListView mSelectedFiles;
private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter();
private final Map<Uri, Bitmap> thumbnailCache = new HashMap<>(); private final Map<Uri, Bitmap> thumbnailCache = new HashMap<>();
@@ -78,21 +78,6 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_files_fragment, container, false); View view = inflater.inflate(R.layout.encrypt_files_fragment, container, false);
View vEncryptFile = view.findViewById(R.id.action_encrypt_file);
vEncryptFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
encryptClicked(false);
}
});
mShareFile = view.findViewById(R.id.action_encrypt_share);
mShareFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
encryptClicked(true);
}
});
mAddView = inflater.inflate(R.layout.file_list_entry_add, null); mAddView = inflater.inflate(R.layout.file_list_entry_add, null);
mAddView.setOnClickListener(new View.OnClickListener() { mAddView.setOnClickListener(new View.OnClickListener() {
@Override @Override
@@ -108,8 +93,10 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
} }
private void addInputUri() { private void addInputUri() {
@@ -191,6 +178,24 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt
return false; return false;
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.encrypt_save: {
encryptClicked(false);
break;
}
case R.id.encrypt_share: {
encryptClicked(true);
break;
}
default: {
return super.onOptionsItemSelected(item);
}
}
return true;
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) { switch (requestCode) {

View File

@@ -72,7 +72,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
private ArrayList<Uri> mInputUris; private ArrayList<Uri> mInputUris;
private ArrayList<Uri> mOutputUris; private ArrayList<Uri> mOutputUris;
private String mMessage = ""; private String mMessage = "";
private boolean mUseCompression; private boolean mUseCompression = true;
public boolean isModeSymmetric() { public boolean isModeSymmetric() {
return MODE_SYMMETRIC == mCurrentMode; return MODE_SYMMETRIC == mCurrentMode;

View File

@@ -23,6 +23,7 @@ import android.support.v4.app.Fragment;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
@@ -33,8 +34,6 @@ public class EncryptTextFragment extends Fragment {
public static final String ARG_TEXT = "text"; public static final String ARG_TEXT = "text";
private TextView mText; private TextView mText;
private View mEncryptShare;
private View mEncryptClipboard;
private EncryptActivityInterface mEncryptInterface; private EncryptActivityInterface mEncryptInterface;
@@ -72,24 +71,16 @@ public class EncryptTextFragment extends Fragment {
mEncryptInterface.setMessage(s.toString()); mEncryptInterface.setMessage(s.toString());
} }
}); });
mEncryptClipboard = view.findViewById(R.id.action_encrypt_clipboard);
mEncryptShare = view.findViewById(R.id.action_encrypt_share);
mEncryptClipboard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mEncryptInterface.startEncrypt(false);
}
});
mEncryptShare.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mEncryptInterface.startEncrypt(true);
}
});
return view; return view;
} }
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
@@ -100,4 +91,22 @@ public class EncryptTextFragment extends Fragment {
mText.setText(text); mText.setText(text);
} }
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.encrypt_copy: {
mEncryptInterface.startEncrypt(false);
break;
}
case R.id.encrypt_share: {
mEncryptInterface.startEncrypt(true);
break;
}
default: {
return super.onOptionsItemSelected(item);
}
}
return true;
}
} }

View File

@@ -76,8 +76,8 @@ public class ViewKeyAdvActivity extends BaseActivity implements
mExportHelper = new ExportHelper(this); mExportHelper = new ExportHelper(this);
mProviderHelper = new ProviderHelper(this); mProviderHelper = new ProviderHelper(this);
mViewPager = (ViewPager) findViewById(R.id.view_key_pager); mViewPager = (ViewPager) findViewById(R.id.pager);
mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.view_key_sliding_tab_layout); mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.sliding_tab_layout);
int switchToTab = TAB_MAIN; int switchToTab = TAB_MAIN;
Intent intent = getIntent(); Intent intent = getIntent();

View File

@@ -33,8 +33,6 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
@@ -44,7 +42,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.ui.widget.EmailEditText; import org.sufficientlysecure.keychain.ui.widget.EmailEditText;
import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.ui.widget.NameEditText;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
public class AddUserIdDialogFragment extends DialogFragment implements OnEditorActionListener { public class AddUserIdDialogFragment extends DialogFragment implements OnEditorActionListener {
@@ -57,7 +55,7 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA
public static final String MESSAGE_DATA_USER_ID = "user_id"; public static final String MESSAGE_DATA_USER_ID = "user_id";
private Messenger mMessenger; private Messenger mMessenger;
private AutoCompleteTextView mName; private NameEditText mName;
private EmailEditText mEmail; private EmailEditText mEmail;
private EditText mComment; private EditText mComment;
@@ -81,11 +79,6 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA
mMessenger = getArguments().getParcelable(ARG_MESSENGER); mMessenger = getArguments().getParcelable(ARG_MESSENGER);
String predefinedName = getArguments().getString(ARG_NAME); String predefinedName = getArguments().getString(ARG_NAME);
ArrayAdapter<String> autoCompleteEmailAdapter = new ArrayAdapter<>
(getActivity(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserEmails(getActivity())
);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
alert.setTitle(R.string.edit_key_action_add_identity); alert.setTitle(R.string.edit_key_action_add_identity);
@@ -94,16 +87,12 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA
View view = inflater.inflate(R.layout.add_user_id_dialog, null); View view = inflater.inflate(R.layout.add_user_id_dialog, null);
alert.setView(view); alert.setView(view);
mName = (AutoCompleteTextView) view.findViewById(R.id.add_user_id_name); mName = (NameEditText) view.findViewById(R.id.add_user_id_name);
mEmail = (EmailEditText) view.findViewById(R.id.add_user_id_address); mEmail = (EmailEditText) view.findViewById(R.id.add_user_id_address);
mComment = (EditText) view.findViewById(R.id.add_user_id_comment); mComment = (EditText) view.findViewById(R.id.add_user_id_comment);
mName.setText(predefinedName); mName.setText(predefinedName);
mEmail.setThreshold(1); // Start working from first character
mEmail.setAdapter(autoCompleteEmailAdapter);
alert.setPositiveButton(android.R.string.ok, new OnClickListener() { alert.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
@@ -118,14 +107,6 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA
} }
}); });
mName.setThreshold(1); // Start working from first character
mName.setAdapter(
new ArrayAdapter<>
(getActivity(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserNames(getActivity())
)
);
alert.setNegativeButton(android.R.string.cancel, new OnClickListener() { alert.setNegativeButton(android.R.string.cancel, new OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {

View File

@@ -28,8 +28,10 @@ import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.widget.Toast; import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
import java.io.File; import java.io.File;
@@ -69,41 +71,44 @@ public class DeleteFileDialogFragment extends DialogFragment {
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
dismiss(); dismiss();
String scheme = deleteUri.getScheme();
if(scheme.equals(ContentResolver.SCHEME_FILE)) { // NOTE: Use Toasts, not Snackbars. When sharing to another application snackbars
if(new File(deleteUri.getPath()).delete()) { // would not show up!
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
return; // Use DocumentsContract on Android >= 4.4
} if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
} try {
else if(scheme.equals(ContentResolver.SCHEME_CONTENT)) {
// We can not securely delete Uris, so just use usual delete on them
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) { if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) {
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful,
deleteFilename), Toast.LENGTH_LONG).show();
return; return;
} }
} } catch (UnsupportedOperationException e) {
Log.d(Constants.TAG, "Catched UnsupportedOperationException, can happen when delete is not supported!", e);
if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
return;
}
// some Uri's a ContentResolver fails to delete is handled by the java.io.File's delete
// via the path of the Uri
if(new File(deleteUri.getPath()).delete()) {
Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show();
return;
} }
} }
Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed, try {
deleteFilename), Toast.LENGTH_SHORT).show(); if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) {
Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful,
deleteFilename), Toast.LENGTH_LONG).show();
return;
}
} catch (UnsupportedOperationException e) {
Log.d(Constants.TAG, "Catched UnsupportedOperationException, can happen when delete is not supported!", e);
}
// some Uri's a ContentResolver fails to delete is handled by the java.io.File's delete
// via the path of the Uri
if (new File(deleteUri.getPath()).delete()) {
Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful,
deleteFilename), Toast.LENGTH_LONG).show();
return;
}
// Note: We can't delete every file... // Note: We can't delete every file...
// If possible we should find out if deletion is possible before even showing the option to do so. Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed,
deleteFilename), Toast.LENGTH_LONG).show();
} }
}); });
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

View File

@@ -43,8 +43,7 @@ import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.widget.PasswordEditText; import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthView;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener { public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
@@ -57,10 +56,9 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
public static final String MESSAGE_NEW_PASSPHRASE = "new_passphrase"; public static final String MESSAGE_NEW_PASSPHRASE = "new_passphrase";
private Messenger mMessenger; private Messenger mMessenger;
private PasswordEditText mPassphraseEditText; private PassphraseEditText mPassphraseEditText;
private EditText mPassphraseAgainEditText; private EditText mPassphraseAgainEditText;
private CheckBox mNoPassphraseCheckBox; private CheckBox mNoPassphraseCheckBox;
private PasswordStrengthView mPassphraseStrengthView;
/** /**
* Creates new instance of this dialog fragment * Creates new instance of this dialog fragment
@@ -100,11 +98,9 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
View view = inflater.inflate(R.layout.passphrase_repeat_dialog, null); View view = inflater.inflate(R.layout.passphrase_repeat_dialog, null);
alert.setView(view); alert.setView(view);
mPassphraseEditText = (PasswordEditText) view.findViewById(R.id.passphrase_passphrase); mPassphraseEditText = (PassphraseEditText) view.findViewById(R.id.passphrase_passphrase);
mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again); mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase); mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase);
mPassphraseStrengthView = (PasswordStrengthView) view.findViewById(R.id.passphrase_repeat_passphrase_strength);
mPassphraseEditText.setPasswordStrengthView(mPassphraseStrengthView);
if (TextUtils.isEmpty(oldPassphrase)) { if (TextUtils.isEmpty(oldPassphrase)) {

View File

@@ -25,6 +25,7 @@ import android.text.InputType;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Patterns; import android.util.Patterns;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView; import android.widget.AutoCompleteTextView;
@@ -34,35 +35,33 @@ import org.sufficientlysecure.keychain.util.ContactHelper;
import java.util.regex.Matcher; import java.util.regex.Matcher;
public class EmailEditText extends AutoCompleteTextView { public class EmailEditText extends AutoCompleteTextView {
EmailEditText emailEditText;
public EmailEditText(Context context) { public EmailEditText(Context context) {
super(context); super(context);
emailEditText = this; init();
this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
this.addTextChangedListener(textWatcher);
} }
public EmailEditText(Context context, AttributeSet attrs) { public EmailEditText(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
emailEditText = this; init();
this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
this.addTextChangedListener(textWatcher);
} }
public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr) { public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
emailEditText = this; init();
this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
this.addTextChangedListener(textWatcher);
} }
@TargetApi(Build.VERSION_CODES.LOLLIPOP) @TargetApi(Build.VERSION_CODES.LOLLIPOP)
public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { public EmailEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes); super(context, attrs, defStyleAttr, defStyleRes);
emailEditText = this; init();
}
private void init() {
this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
this.addTextChangedListener(textWatcher); this.addTextChangedListener(textWatcher);
removeFlag();
initAdapter();
} }
TextWatcher textWatcher = new TextWatcher() { TextWatcher textWatcher = new TextWatcher() {
@@ -82,16 +81,32 @@ public class EmailEditText extends AutoCompleteTextView {
if (email.length() > 0) { if (email.length() > 0) {
Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email); Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
if (emailMatcher.matches()) { if (emailMatcher.matches()) {
emailEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0, EmailEditText.this.setCompoundDrawablesWithIntrinsicBounds(0, 0,
R.drawable.uid_mail_ok, 0); R.drawable.uid_mail_ok, 0);
} else { } else {
emailEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0, EmailEditText.this.setCompoundDrawablesWithIntrinsicBounds(0, 0,
R.drawable.uid_mail_bad, 0); R.drawable.uid_mail_bad, 0);
} }
} else { } else {
// remove drawable if email is empty // remove drawable if email is empty
emailEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); EmailEditText.this.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
} }
} }
}; };
private void initAdapter() {
setThreshold(1); // Start working from first character
setAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserEmails(getContext())));
}
/**
* Hack to re-enable keyboard auto correction in AutoCompleteTextView.
* From http://stackoverflow.com/a/22512858
*/
private void removeFlag() {
int inputType = getInputType();
inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
setRawInputType(inputType);
}
} }

View File

@@ -17,32 +17,54 @@
package org.sufficientlysecure.keychain.ui.widget; package org.sufficientlysecure.keychain.ui.widget;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.os.Build;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView; import android.widget.AutoCompleteTextView;
/** import org.sufficientlysecure.keychain.util.ContactHelper;
* Hack to re-enable keyboard auto correction in AutoCompleteTextView.
* From http://stackoverflow.com/a/22512858
*/
public class AutoCorrectAutoCompleteTextView extends AutoCompleteTextView {
public AutoCorrectAutoCompleteTextView(Context context) { public class NameEditText extends AutoCompleteTextView {
public NameEditText(Context context) {
super(context); super(context);
removeFlag(); init();
} }
public AutoCorrectAutoCompleteTextView(Context context, AttributeSet attrs) { public NameEditText(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
removeFlag(); init();
} }
public AutoCorrectAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) { public NameEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyle); super(context, attrs, defStyleAttr);
removeFlag(); init();
} }
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public NameEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
removeFlag();
initAdapter();
}
private void initAdapter() {
setThreshold(1); // Start working from first character
setAdapter(new ArrayAdapter<>(
getContext(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserNames(getContext())));
}
/**
* Hack to re-enable keyboard auto correction in AutoCompleteTextView.
* From http://stackoverflow.com/a/22512858
*/
private void removeFlag() { private void removeFlag() {
int inputType = getInputType(); int inputType = getInputType();
inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE; inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.EditText;
import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthBarView;
public class PassphraseEditText extends EditText {
PasswordStrengthBarView mPasswordStrengthBarView;
int mPasswordBarWidth;
int mPasswordBarHeight;
float barGap;
public PassphraseEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mPasswordBarHeight = (int) (8 * getResources().getDisplayMetrics().density);
mPasswordBarWidth = (int) (50 * getResources().getDisplayMetrics().density);
barGap = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
getContext().getResources().getDisplayMetrics());
this.setPadding(getPaddingLeft(), getPaddingTop(),
getPaddingRight() + (int) barGap + mPasswordBarWidth, getPaddingBottom());
mPasswordStrengthBarView = new PasswordStrengthBarView(context, attrs);
mPasswordStrengthBarView.setShowGuides(false);
this.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mPasswordStrengthBarView.setPassword(s.toString());
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mPasswordStrengthBarView.layout(0, 0, mPasswordBarWidth, mPasswordBarHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float translateX = getScrollX() + canvas.getWidth() - mPasswordBarWidth;
float translateY = (canvas.getHeight() - mPasswordBarHeight) / 2;
canvas.translate(translateX, translateY);
mPasswordStrengthBarView.draw(canvas);
canvas.translate(-translateX, -translateY);
}
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.widget;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.widget.EditText;
import org.sufficientlysecure.keychain.ui.widget.passwordstrengthindicator.PasswordStrengthView;
/**
* Developer: chipset
* Package : org.sufficientlysecure.keychain.layouts
* Project : open-keychain
* Date : 6/3/15
*/
public class PasswordEditText extends EditText {
PasswordEditText passwordEditText;
PasswordStrengthView passwordStrengthView;
public PasswordEditText(Context context) {
super(context);
passwordEditText = this;
this.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_PASSWORD);
this.addTextChangedListener(textWatcher);
}
public PasswordEditText(Context context, AttributeSet attrs) {
super(context, attrs);
passwordEditText = this;
this.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_PASSWORD);
this.addTextChangedListener(textWatcher);
}
public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
passwordEditText = this;
this.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_PASSWORD);
this.addTextChangedListener(textWatcher);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
passwordEditText = this;
this.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_PASSWORD);
this.addTextChangedListener(textWatcher);
}
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable editable) {
String passphrase = editable.toString();
passwordStrengthView.setPassword(passphrase);
}
};
// public PasswordStrengthView getPasswordStrengthView() {
// return passwordStrengthView;
// }
public void setPasswordStrengthView(PasswordStrengthView mPasswordStrengthView) {
this.passwordStrengthView = mPasswordStrengthView;
}
}

View File

@@ -56,9 +56,6 @@ import org.sufficientlysecure.keychain.R;
*/ */
public class PasswordStrengthView extends View { public class PasswordStrengthView extends View {
protected static final int COLOR_FAIL = Color.parseColor("#e74c3c");
protected static final int COLOR_WEAK = Color.parseColor("#e67e22");
protected static final int COLOR_STRONG = Color.parseColor("#2ecc71");
protected int mMinWidth; protected int mMinWidth;
protected int mMinHeight; protected int mMinHeight;
@@ -100,6 +97,11 @@ public class PasswordStrengthView extends View {
public PasswordStrengthView(Context context, AttributeSet attrs) { public PasswordStrengthView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
int COLOR_FAIL = context.getResources().getColor(R.color.android_red_light);
int COLOR_WEAK = context.getResources().getColor(R.color.android_orange_light);
int COLOR_STRONG = context.getResources().getColor(R.color.android_green_light);
TypedArray style = context.getTheme().obtainStyledAttributes( TypedArray style = context.getTheme().obtainStyledAttributes(
attrs, attrs,
R.styleable.PasswordStrengthView, R.styleable.PasswordStrengthView,

View File

@@ -43,9 +43,11 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher;
public class ContactHelper { public class ContactHelper {
@@ -54,6 +56,17 @@ public class ContactHelper {
public static List<String> getPossibleUserEmails(Context context) { public static List<String> getPossibleUserEmails(Context context) {
Set<String> accountMails = getAccountEmails(context); Set<String> accountMails = getAccountEmails(context);
accountMails.addAll(getMainProfileContactEmails(context)); accountMails.addAll(getMainProfileContactEmails(context));
// remove items that are not an email
Iterator<String> it = accountMails.iterator();
while (it.hasNext()) {
String email = it.next();
Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
if (!emailMatcher.matches()) {
it.remove();
}
}
// now return the Set (without duplicates) as a List // now return the Set (without duplicates) as a List
return new ArrayList<>(accountMails); return new ArrayList<>(accountMails);
} }
@@ -62,6 +75,17 @@ public class ContactHelper {
Set<String> accountMails = getAccountEmails(context); Set<String> accountMails = getAccountEmails(context);
Set<String> names = getContactNamesFromEmails(context, accountMails); Set<String> names = getContactNamesFromEmails(context, accountMails);
names.addAll(getMainProfileContactName(context)); names.addAll(getMainProfileContactName(context));
// remove items that are an email
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String email = it.next();
Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
if (emailMatcher.matches()) {
it.remove();
}
}
return new ArrayList<>(names); return new ArrayList<>(names);
} }
@@ -75,9 +99,7 @@ public class ContactHelper {
final Account[] accounts = AccountManager.get(context).getAccounts(); final Account[] accounts = AccountManager.get(context).getAccounts();
final Set<String> emailSet = new HashSet<>(); final Set<String> emailSet = new HashSet<>();
for (Account account : accounts) { for (Account account : accounts) {
if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) { emailSet.add(account.name);
emailSet.add(account.name);
}
} }
return emailSet; return emailSet;
} }
@@ -256,7 +278,7 @@ public class ContactHelper {
} }
public static Bitmap loadPhotoByMasterKeyId(ContentResolver contentResolver, long masterKeyId, public static Bitmap loadPhotoByMasterKeyId(ContentResolver contentResolver, long masterKeyId,
boolean highRes) { boolean highRes) {
if (masterKeyId == -1) { if (masterKeyId == -1) {
return null; return null;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Some files were not shown because too many files have changed in this diff Show More