From fbd098c22b13469c001671f5ef291f053188feac Mon Sep 17 00:00:00 2001 From: boun <boun@gmx.de> Date: Thu, 21 Feb 2013 20:05:53 +0100 Subject: [PATCH 1/8] Create README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf1be54 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +notepad +======= + +Fork of the excellent OpenIntents Notepad, to add some some MIUI pastel color love. + +Uses some code/pngs from https://github.com/ebraminio/miuinotes + From a3a378783c180c1f85794889786b64724d4ab60b Mon Sep 17 00:00:00 2001 From: Benedikt Elser <boun@gmx.de> Date: Thu, 21 Feb 2013 20:06:19 +0100 Subject: [PATCH 2/8] Initial MIUI Love --- NotePad/AndroidManifest.xml | 5 +- NotePad/res/drawable/header_bg_brown.xml | 23 + NotePad/res/drawable/note_item_bg_blue.xml | 38 + NotePad/res/drawable/note_item_bg_green.xml | 38 + NotePad/res/drawable/note_item_bg_grey.xml | 38 + NotePad/res/drawable/note_item_bg_pink.xml | 38 + NotePad/res/drawable/note_item_bg_yellow.xml | 38 + NotePad/res/drawable/notes_background.jpg | Bin 0 -> 77907 bytes .../res/drawable/notes_btn_changecolors.png | Bin 0 -> 704 bytes NotePad/res/drawable/transparent72.png | Bin 0 -> 240 bytes NotePad/res/drawable/zhengwen_xuanyanse.png | Bin 0 -> 4671 bytes NotePad/res/layout/note_editor.xml | 45 +- NotePad/res/layout/noteslist.xml | 17 +- NotePad/res/layout/noteslist_item.xml | 24 +- NotePad/res/values/colors.xml | 28 + NotePad/res/values/strings.xml | 2 + NotePad/res/values/styles.xml | 33 + .../org/openintents/notepad/NoteEditor.java | 1319 +++++++++-------- .../src/org/openintents/notepad/NotePad.java | 88 +- .../openintents/notepad/NotePadProvider.java | 264 ++-- .../notepad/noteslist/NotesList.java | 774 +++++----- .../notepad/noteslist/NotesListCursor.java | 131 +- .../noteslist/NotesListCursorAdapter.java | 105 +- .../notepad/noteslist/NotesListItemView.java | 41 +- .../notepad/wrappers/WrapActionBar.java | 25 +- 25 files changed, 1740 insertions(+), 1374 deletions(-) create mode 100644 NotePad/res/drawable/header_bg_brown.xml create mode 100644 NotePad/res/drawable/note_item_bg_blue.xml create mode 100644 NotePad/res/drawable/note_item_bg_green.xml create mode 100644 NotePad/res/drawable/note_item_bg_grey.xml create mode 100644 NotePad/res/drawable/note_item_bg_pink.xml create mode 100644 NotePad/res/drawable/note_item_bg_yellow.xml create mode 100644 NotePad/res/drawable/notes_background.jpg create mode 100644 NotePad/res/drawable/notes_btn_changecolors.png create mode 100644 NotePad/res/drawable/transparent72.png create mode 100644 NotePad/res/drawable/zhengwen_xuanyanse.png create mode 100644 NotePad/res/values/colors.xml create mode 100644 NotePad/res/values/styles.xml diff --git a/NotePad/AndroidManifest.xml b/NotePad/AndroidManifest.xml index 5131bce..578983b 100644 --- a/NotePad/AndroidManifest.xml +++ b/NotePad/AndroidManifest.xml @@ -42,13 +42,14 @@ [10054] 1.1.1: 2009-05-16 [10052] 1.1.0: 2009-02-02 --> - <uses-sdk android:minSdkVersion="2" + <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="15" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> <application android:icon="@drawable/ic_launcher_notepad" android:label="@string/app_name" + android:theme="@style/MyActionBar" ><!-- android:debuggable="true" --> <!-- aTrackDog metadata --> <meta-data android:name="com.a0soft.gphone.aTrackDog.testVersion" @@ -105,7 +106,7 @@ </activity> <activity android:name="NoteEditor" - android:theme="@android:style/Theme.Light" + android:theme="@style/MyActionBar" android:label="@string/title_note" android:windowSoftInputMode="stateHidden" > diff --git a/NotePad/res/drawable/header_bg_brown.xml b/NotePad/res/drawable/header_bg_brown.xml new file mode 100644 index 0000000..4e0cbda --- /dev/null +++ b/NotePad/res/drawable/header_bg_brown.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:drawable="@drawable/biaoqian_huang" /> + +</selector --> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <gradient + android:startColor="@color/lightBrown" + android:endColor="@color/darkBrown" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkBrown" /> + </shape> + </item> + + </selector> diff --git a/NotePad/res/drawable/note_item_bg_blue.xml b/NotePad/res/drawable/note_item_bg_blue.xml new file mode 100644 index 0000000..b74f813 --- /dev/null +++ b/NotePad/res/drawable/note_item_bg_blue.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:drawable="@drawable/biaoqian_huang" /> + +</selector --> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" > + <shape> + <gradient + android:startColor="@color/darkBabyBlue" + android:endColor="@color/darkestBabyBlue" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkBabyBlue" /> + <corners + android:radius="3dp" /> + </shape> + </item> + <item> + <shape> + <gradient + android:startColor="@color/lightBabyBlue" + android:endColor="@color/darkBabyBlue" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkBabyBlue" /> + <corners + android:radius="3dp" /> + </shape> + </item> + + </selector> diff --git a/NotePad/res/drawable/note_item_bg_green.xml b/NotePad/res/drawable/note_item_bg_green.xml new file mode 100644 index 0000000..e851a61 --- /dev/null +++ b/NotePad/res/drawable/note_item_bg_green.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:drawable="@drawable/biaoqian_huang" /> + +</selector --> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" > + <shape> + <gradient + android:startColor="@color/darkGreen" + android:endColor="@color/darkestGreen" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkGreen" /> + <corners + android:radius="3dp" /> + </shape> + </item> + <item> + <shape> + <gradient + android:startColor="@color/lightGreen" + android:endColor="@color/darkGreen" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkGreen" /> + <corners + android:radius="3dp" /> + </shape> + </item> + + </selector> diff --git a/NotePad/res/drawable/note_item_bg_grey.xml b/NotePad/res/drawable/note_item_bg_grey.xml new file mode 100644 index 0000000..bdf7bc3 --- /dev/null +++ b/NotePad/res/drawable/note_item_bg_grey.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:drawable="@drawable/biaoqian_huang" /> + +</selector --> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" > + <shape> + <gradient + android:startColor="@color/darkGray1" + android:endColor="@color/darkGray2" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkGray1" /> + <corners + android:radius="3dp" /> + </shape> + </item> + <item> + <shape> + <gradient + android:startColor="@color/lightGray" + android:endColor="@color/darkGray1" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkGray1" /> + <corners + android:radius="3dp" /> + </shape> + </item> + + </selector> diff --git a/NotePad/res/drawable/note_item_bg_pink.xml b/NotePad/res/drawable/note_item_bg_pink.xml new file mode 100644 index 0000000..ed5a5b9 --- /dev/null +++ b/NotePad/res/drawable/note_item_bg_pink.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:drawable="@drawable/biaoqian_huang" /> + +</selector --> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" > + <shape> + <gradient + android:startColor="@color/darkPink" + android:endColor="@color/darkestPink" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkPink" /> + <corners + android:radius="3dp" /> + </shape> + </item> + <item> + <shape> + <gradient + android:startColor="@color/lightPink" + android:endColor="@color/darkPink" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkPink" /> + <corners + android:radius="3dp" /> + </shape> + </item> + + </selector> diff --git a/NotePad/res/drawable/note_item_bg_yellow.xml b/NotePad/res/drawable/note_item_bg_yellow.xml new file mode 100644 index 0000000..957c339 --- /dev/null +++ b/NotePad/res/drawable/note_item_bg_yellow.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> + <item android:drawable="@drawable/biaoqian_huang" /> + +</selector --> +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" > + <shape> + <gradient + android:startColor="@color/darkYellow" + android:endColor="@color/darkestYellow" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkYellow" /> + <corners + android:radius="3dp" /> + </shape> + </item> + <item> + <shape> + <gradient + android:startColor="@color/lightYellow" + android:endColor="@color/darkYellow" + android:angle="270" /> + <stroke + android:width="2dp" + android:color="@color/darkYellow" /> + <corners + android:radius="3dp" /> + </shape> + </item> + + </selector> diff --git a/NotePad/res/drawable/notes_background.jpg b/NotePad/res/drawable/notes_background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2614eaa6d1c87b03dbfa0d2d1f148e71d8ea83c4 GIT binary patch literal 77907 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 literal 0 HcmV?d00001 diff --git a/NotePad/res/drawable/notes_btn_changecolors.png b/NotePad/res/drawable/notes_btn_changecolors.png new file mode 100644 index 0000000000000000000000000000000000000000..6f6c45cc16bf51d06f3c736f5eeb472f1c965b91 GIT binary patch literal 704 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX3?zBp#Z3TGw*!1aT!Azi`1<wh|NsAig8%;g z1CoFL{yn{`WACzreajP99bZ0SN6*BaJwWl_zki?Flzw%0?)ANSvyM(%bbjuVi}Qiv zzkdCCbiCy8iIO#Umao0L;>V94-@bkO^5x5?PoF+~`0(!CyEkv%+&(#R`}NJQUcGwp z;>Gjl&v#GUzrJ+KhO(`F^NtsG94P8I`0UxUJ#`0<wVXcQdbV=nx%!zm8)w~m`t<3g zo*S2YZ?-Rb*0K2clP6DJzI=IM;pMp-?!A8f`qHIKK--Z)3IDd+K)z>5kY6w(3nwo> z-_ifF|22S~0|7k<^<N)K6Qs_`SOvtyo|Cz9oPmMS+tbA{MC1J0%cskl3<Me;a%AXc zY*pxb)Vf=2%dL*2Jq=-3_Wc(QeSTnOZ^_mA-@21do)idrRPiv=CR}Mr$htiuA)3=U z!fSQcoDz(ivLxy+@2cx6D=*fx&*JqIs#H4Bbt&lfgj+#V`mVKZ>05MyNw8|yx^L_O z@mEW8Et=Y9t@|#QBk|TT?6$$K#cS3jGR#)nl&LgZZ9}SJwAiLp#@l9_a+PnJZFsC; z&9~_>!*0Dzua$P|ZFt`M`QWj6<|o-_SIB*EPdreUc)-zMZmrYiOo21v@fVWhSPo3l zJ1i=qry1)mtq~Q>btYoRUB}xKHfGc}d=pGQP`Kw->e@#Y#V2kZ`DkyDe4<A&Jw3R~ zN3*D`_`dtM+9z)!Cq0?LU*<C@*zSg=r<_i`c-jB1Jr&=$tnS+zO^;i*eZKnLb<?Np o)(_M=wO9RQQdFJJ&3Nq}+>f=Y^Otbznt|fZ)78&qol`;+053px00000 literal 0 HcmV?d00001 diff --git a/NotePad/res/drawable/transparent72.png b/NotePad/res/drawable/transparent72.png new file mode 100644 index 0000000000000000000000000000000000000000..65343ba06e71b18cb0fe609ab6a0f59d0ae93d91 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!oCO|{#S9GG!XV7ZFl&wkP*5S+ zBgmJ5p-Pp3p`n?9;pcxK{gQ#9)PRBERRRNp)eHs(@%%~gN8NyG%RF5iLn>~)xnRi1 zz`((*u(kgA%meqCl`eR8-PRCL@tC0C*u=u=1fhgfI6yohkT8@2@)e<qgj&FAfwBTH lMUG9VM(m3KTKWG!GlR4bbMN}?@`gYzgQu&X%Q~loCII<kJAnWI literal 0 HcmV?d00001 diff --git a/NotePad/res/drawable/zhengwen_xuanyanse.png b/NotePad/res/drawable/zhengwen_xuanyanse.png new file mode 100644 index 0000000000000000000000000000000000000000..33ceb63ef586a1b4ccb8b18a235ad937ff17d244 GIT binary patch literal 4671 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 literal 0 HcmV?d00001 diff --git a/NotePad/res/layout/note_editor.xml b/NotePad/res/layout/note_editor.xml index 8bd8c15..39c390d 100644 --- a/NotePad/res/layout/note_editor.xml +++ b/NotePad/res/layout/note_editor.xml @@ -16,15 +16,50 @@ * limitations under the License. --> -<view xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:background="@android:color/white" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + +<view android:id="@+id/note" class="org.openintents.notepad.NoteEditor$LinedEditText" - android:id="@+id/note" android:layout_width="fill_parent" android:layout_height="fill_parent" - android:background="@android:color/transparent" android:padding="5dip" android:scrollbars="vertical" android:fadingEdge="vertical" android:gravity="top" - android:capitalize="sentences" -/> \ No newline at end of file + android:capitalize="sentences"/> + + <LinearLayout android:id="@+id/editor_color" + android:clickable="true" + android:orientation="horizontal" + android:layout_width="290.0dp" android:layout_height="wrap_content" + android:layout_gravity="top|center" android:gravity="center" + android:layout_marginTop="70.0dp" + android:background="@drawable/zhengwen_xuanyanse" + android:visibility="gone"> + <ImageView android:id="@+id/editor_color_yellow" + android:layout_weight="1.0" android:layout_width="wrap_content" + android:layout_height="wrap_content" android:scaleType="center" + android:background="@drawable/transparent72" /> + <ImageView android:id="@+id/editor_color_pink" + android:layout_weight="1.0" android:layout_width="wrap_content" + android:layout_height="wrap_content" android:scaleType="center" + android:background="@drawable/transparent72" /> + <ImageView android:id="@+id/editor_color_blue" + android:layout_weight="1.0" android:layout_width="wrap_content" + android:layout_height="wrap_content" android:scaleType="center" + android:background="@drawable/transparent72" /> + <ImageView android:id="@+id/editor_color_green" + android:layout_weight="1.0" android:layout_width="wrap_content" + android:layout_height="wrap_content" android:scaleType="center" + android:background="@drawable/transparent72" /> + <ImageView android:id="@+id/editor_color_gray" + android:layout_weight="1.0" android:layout_width="wrap_content" + android:layout_height="wrap_content" android:scaleType="center" + android:background="@drawable/transparent72" /> + </LinearLayout> + +</FrameLayout> diff --git a/NotePad/res/layout/noteslist.xml b/NotePad/res/layout/noteslist.xml index ba1a38c..052d60b 100644 --- a/NotePad/res/layout/noteslist.xml +++ b/NotePad/res/layout/noteslist.xml @@ -17,22 +17,9 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" + android:background="@drawable/notes_background" android:layout_width="fill_parent" android:layout_height="fill_parent"> - <!-- - <LinearLayout - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> - - <Button android:id="@+id/add" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/menu_insert" - android:layout_gravity="center" /> - - </LinearLayout> - --> <Spinner android:id="@+id/tagselection" android:layout_width="fill_parent" @@ -50,7 +37,7 @@ find it --> <ListView android:id="@android:id/list" android:layout_width="fill_parent" - android:layout_height="fill_parent" + android:layout_height="fill_parent" android:fastScrollEnabled="true" android:drawSelectorOnTop="false"/> diff --git a/NotePad/res/layout/noteslist_item.xml b/NotePad/res/layout/noteslist_item.xml index b2412f9..b703ed1 100644 --- a/NotePad/res/layout/noteslist_item.xml +++ b/NotePad/res/layout/noteslist_item.xml @@ -16,37 +16,36 @@ * limitations under the License. */ --> - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:layout_marginLeft="8dip" android:layout_marginRight="12dip" android:minHeight="?android:attr/listPreferredItemHeight" - ><!-- android:layout_marginTop="8dip" android:layout_marginBottom="8dip" - --> - <LinearLayout + > + <LinearLayout android:orientation="vertical" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="center_vertical" - android:layout_marginLeft="5dip" - ><!-- android:layout_alignParentLeft="true" - --> + > <org.openintents.notepad.noteslist.MarqueeTextView android:id="@+id/title" - android:layout_height="wrap_content" - android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_width="fill_parent" + android:drawablePadding="1dp" android:textAppearance="?android:attr/textAppearanceLarge" - android:singleLine="true" + android:singleLine="true" + android:background="@drawable/note_item_bg_yellow" android:ellipsize="end" android:scrollHorizontally="true" + android:textColor="#ff4b4b4b" + android:padding="20dp" /> <!-- CheckedTextView: android:checkMark="?android:attr/listChoiceIndicatorMultiple" --> <TextView - android:id="@+id/info" + android:id="@+id/info" android:layout_height="wrap_content" android:layout_width="wrap_content" android:visibility="gone" @@ -62,7 +61,6 @@ android:layout_gravity="center_vertical" /> - </LinearLayout> <!-- diff --git a/NotePad/res/values/colors.xml b/NotePad/res/values/colors.xml new file mode 100644 index 0000000..4ed7ef9 --- /dev/null +++ b/NotePad/res/values/colors.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Note colors --> + <color name="lightYellow">#faffd1</color> + <color name="darkYellow">#eef3c1</color> + <color name="darkestYellow">#cdd0a4</color> + + <color name="gray">#CCCCCC</color> + <color name="lightGray">#EFEFEF</color> + <color name="darkGray1">#848484</color> + <color name="darkGray2">#2D2D2D</color> + + <color name="lightBrown">#825f3f</color> + <color name="darkBrown">#5b371d</color> + + <color name="lightBabyBlue">#ddf2ff</color> + <color name="darkBabyBlue">#ddf2ff</color> + <color name="darkestBabyBlue">#acd6f1</color> + + + <color name="lightPink">#ffeded</color> + <color name="darkPink">#ffeded</color> + <color name="darkestPink">#d1c2c2</color> + + <color name="lightGreen">#eafecf</color> + <color name="darkGreen">#cfe08a</color> + <color name="darkestGreen">#b3c665</color> +</resources> diff --git a/NotePad/res/values/strings.xml b/NotePad/res/values/strings.xml index b5fe4e9..63a324f 100644 --- a/NotePad/res/values/strings.xml +++ b/NotePad/res/values/strings.xml @@ -68,6 +68,8 @@ <!-- <string name="no_notes">Note list is empty.</string> --> <string name="menu_share">Share</string> + <string name="menu_color">Color</string> + <string name="empty_note">Empty note</string> <string name="share_not_available">No application available for sharing.</string> diff --git a/NotePad/res/values/styles.xml b/NotePad/res/values/styles.xml new file mode 100644 index 0000000..fc6ae30 --- /dev/null +++ b/NotePad/res/values/styles.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <!-- the theme applied to the application or activity --> + <style name="MyActionBar" parent="android:style/Theme.Holo.Light"> + <item name="android:actionBarStyle">@style/MyActionBar3</item> + <!-- other activity and action bar styles here --> + </style> + + <!-- style for the action bar backgrounds --> + <style name="MyActionBar3" parent="android:style/Widget.Holo.Light.ActionBar"> + <item name="android:background">@drawable/header_bg_brown</item> + </style> + + <style name="MyActionBar2" parent="android:style/Widget.Holo.Light.ActionBar"> + + <!-- item name="android:background">@drawable/beijing_toubu</item --> + </style> +</resources> diff --git a/NotePad/src/org/openintents/notepad/NoteEditor.java b/NotePad/src/org/openintents/notepad/NoteEditor.java index 37122b0..228eebc 100644 --- a/NotePad/src/org/openintents/notepad/NoteEditor.java +++ b/NotePad/src/org/openintents/notepad/NoteEditor.java @@ -88,16 +88,19 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; import android.view.Window; import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; /** - * A generic activity for editing a note in a database. This can be used either - * to simply view a note {@link Intent#ACTION_VIEW}, view and edit a note - * {@link Intent#ACTION_EDIT}, or create a new note {@link Intent#ACTION_INSERT} - * . + * A generic activity for editing a note in a database. This can be used + * either to simply view a note {@link Intent#ACTION_VIEW}, view and edit a note + * {@link Intent#ACTION_EDIT}, or create a new note {@link Intent#ACTION_INSERT}. */ public class NoteEditor extends Activity implements ThemeDialogListener { private static final String TAG = "NoteEditor"; @@ -106,14 +109,16 @@ public class NoteEditor extends Activity implements ThemeDialogListener { /** * Standard projection for the interesting columns of a normal note. */ - private static final String[] PROJECTION = new String[] { Notes._ID, // 0 - Notes.NOTE, // 1 - Notes.TAGS, // 2 - Notes.ENCRYPTED, // 3 - Notes.THEME, // 4 - Notes.SELECTION_START, // 5 - Notes.SELECTION_END, // 6 - Notes.SCROLL_POSITION, // 7 + private static final String[] PROJECTION = new String[] { + Notes._ID, // 0 + Notes.NOTE, // 1 + Notes.TAGS, // 2 + Notes.ENCRYPTED, // 3 + Notes.THEME, // 4 + Notes.SELECTION_START, // 5 + Notes.SELECTION_END, // 6 + Notes.SCROLL_POSITION, // 7 + Notes.COLOR, // 7 }; /** The index of the note column */ private static final int COLUMN_INDEX_ID = 0; @@ -124,7 +129,9 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final int COLUMN_INDEX_SELECTION_START = 5; private static final int COLUMN_INDEX_SELECTION_END = 6; private static final int COLUMN_INDEX_SCROLL_POSITION = 7; + private static final int COLUMN_INDEX_COLOR = 8; + // This is our state data that is stored when freezing. private static final String BUNDLE_ORIGINAL_CONTENT = "original_content"; private static final String BUNDLE_UNDO_REVERT = "undo_revert"; @@ -132,12 +139,13 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final String BUNDLE_URI = "uri"; private static final String BUNDLE_SELECTION_START = "selection_start"; private static final String BUNDLE_SELECTION_STOP = "selection_stop"; - // private static final String BUNDLE_FILENAME = "filename"; + // private static final String BUNDLE_FILENAME = "filename"; private static final String BUNDLE_FILE_CONTENT = "file_content"; private static final String BUNDLE_APPLY_TEXT = "apply_text"; private static final String BUNDLE_APPLY_TEXT_BEFORE = "apply_text_before"; private static final String BUNDLE_APPLY_TEXT_AFTER = "apply_text_after"; + // Identifiers for our menu items. private static final int MENU_REVERT = Menu.FIRST; private static final int MENU_DISCARD = Menu.FIRST + 1; @@ -151,8 +159,9 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final int MENU_SETTINGS = Menu.FIRST + 9; private static final int MENU_SEND = Menu.FIRST + 10; private static final int MENU_WORD_COUNT = Menu.FIRST + 11; + private static final int MENU_COLOR = Menu.FIRST + 12; - // private static final int REQUEST_CODE_ENCRYPT = 1; + //private static final int REQUEST_CODE_ENCRYPT = 1; private static final int REQUEST_CODE_DECRYPT = 2; private static final int REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE = 3; private static final int REQUEST_CODE_SAVE_AS = 4; @@ -166,15 +175,8 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final int DIALOG_UNSAVED_CHANGES = 1; private static final int DIALOG_THEME = 2; private static final int DIALOG_DELETE = 3; - - private static final int GROUP_ID_TEXT_SELECTION_ALTERNATIVE = 1234; // some - // number - // that - // must - // not - // collide - // with - // others + + private static final int GROUP_ID_TEXT_SELECTION_ALTERNATIVE = 1234; // some number that must not collide with others private int mState; private boolean mNoteOnly = false; @@ -196,16 +198,20 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private long mEncrypted; private String mDecryptedText; + private int mColor = -1; + /** - * static string for hack. Only used for configuration changes. + * static string for hack. + * Only used for configuration changes. */ private static String sDecryptedText = null; private static int sSelectionStart = 0; private static int sSelectionStop = 0; + private String mFileContent; - // private String mTags; + // private String mTags; private String mTheme; @@ -215,41 +221,43 @@ public class NoteEditor extends Activity implements ThemeDialogListener { public boolean mTextUpperCaseFont; public int mTextColor; public int mBackgroundPadding; - + /** - * Which features are supported (which columns are available in the - * database)? Everything is supported by default. + * Which features are supported (which columns are available in the database)? + * Everything is supported by default. */ private boolean hasNoteColumn = true; private boolean hasTagsColumn = true; private boolean hasEncryptionColumn = true; + private boolean hasColorColumn = true; private boolean hasThemeColumn = true; private boolean hasSelection_startColumn = true; private boolean hasSelection_endColumn = true; /** - * Lines mode: 0..no line. 2..show lines only where there is text (padding - * width). 3..show lines only where there is text (full width). 4..show - * lines for whole page (padding width). 5..show lines for whole page (full - * width). + * Lines mode: + * 0..no line. + * 2..show lines only where there is text (padding width). + * 3..show lines only where there is text (full width). + * 4..show lines for whole page (padding width). + * 5..show lines for whole page (full width). */ public static int mLinesMode; public static int mLinesColor; - + private static boolean mActionBarAvailable; - + static { try { WrapActionBar.checkAvailable(); mActionBarAvailable = true; - } catch (Throwable t) { + } catch(Throwable t){ mActionBarAvailable = false; } } - + /** - * A custom EditText that draws lines between each line of text that is - * displayed. + * A custom EditText that draws lines between each line of text that is displayed. */ public static class LinedEditText extends EditText { private Rect mRect; @@ -264,8 +272,8 @@ public LinedEditText(Context context, AttributeSet attrs) { mPaint.setStyle(Paint.Style.STROKE); } - @Override - protected void onDraw(Canvas canvas) { + //@Override + protected void onDraws(Canvas canvas) { boolean fullWidth = (mLinesMode & 1) == 1; boolean textlines = (mLinesMode & 2) == 2; boolean pagelines = (mLinesMode & 4) == 4; @@ -291,20 +299,18 @@ protected void onDraw(Canvas canvas) { left = getLeft(); right = getRight(); } - canvas.drawLine(left, baseline + 1, right, baseline + 1, - paint); + canvas.drawLine(left, baseline + 1, right, baseline + 1, paint); } if (pagelines) { // Fill the rest of the page with lines for (int i = count; i < page_size; i++) { baseline += line_height; - canvas.drawLine(left, baseline + 1, right, - baseline + 1, paint); + canvas.drawLine(left, baseline + 1, right, baseline + 1, paint); } } - } - - super.onDraw(canvas); + } + + //super.onDraw(canvas); } } @@ -312,10 +318,9 @@ protected void onDraw(Canvas canvas) { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (debug) - Log.d(TAG, "onCreate()"); + if (debug) Log.d(TAG, "onCreate()"); - if (getIntent().getAction().equals(Intent.ACTION_CREATE_SHORTCUT)) { + if(getIntent().getAction().equals(Intent.ACTION_CREATE_SHORTCUT)) { createShortcut(); return; } @@ -328,13 +333,12 @@ protected void onCreate(Bundle savedInstanceState) { // Usually, sDecryptedText == null. mDecryptedText = sDecryptedText; if (sDecryptedText != null) { - // we use the text right now, + // we use the text right now, // so don't encrypt the text anymore. EncryptActivity.cancelEncrypt(); if (EncryptActivity.getPendingEncryptActivities() == 0) { - if (debug) - Log.d(TAG, "sDecryptedText = null"); + if (debug) Log.d(TAG, "sDecryptedText = null"); // no more encrypt activies will be called sDecryptedText = null; } @@ -346,31 +350,26 @@ protected void onCreate(Bundle savedInstanceState) { // If an instance of this activity had previously stopped, we can // get the original text it started with. if (savedInstanceState != null) { - mOriginalContent = savedInstanceState - .getString(BUNDLE_ORIGINAL_CONTENT); + mOriginalContent = savedInstanceState.getString(BUNDLE_ORIGINAL_CONTENT); mUndoRevert = savedInstanceState.getString(BUNDLE_UNDO_REVERT); mState = savedInstanceState.getInt(BUNDLE_STATE); mUri = Uri.parse(savedInstanceState.getString(BUNDLE_URI)); mSelectionStart = savedInstanceState.getInt(BUNDLE_SELECTION_START); mSelectionStop = savedInstanceState.getInt(BUNDLE_SELECTION_STOP); mFileContent = savedInstanceState.getString(BUNDLE_FILE_CONTENT); - if (mApplyText == null && mApplyTextBefore == null - && mApplyTextAfter == null) { - // Only read values if they had not been set by - // onActivityResult() yet: + if (mApplyText == null && mApplyTextBefore == null && mApplyTextAfter == null) { + // Only read values if they had not been set by onActivityResult() yet: mApplyText = savedInstanceState.getString(BUNDLE_APPLY_TEXT); - mApplyTextBefore = savedInstanceState - .getString(BUNDLE_APPLY_TEXT_BEFORE); - mApplyTextAfter = savedInstanceState - .getString(BUNDLE_APPLY_TEXT_AFTER); + mApplyTextBefore = savedInstanceState.getString(BUNDLE_APPLY_TEXT_BEFORE); + mApplyTextAfter = savedInstanceState.getString(BUNDLE_APPLY_TEXT_AFTER); } } else { // Do some setup based on the action being performed. final Intent intent = getIntent(); + final String action = intent.getAction(); - if (Intent.ACTION_EDIT.equals(action) - || Intent.ACTION_VIEW.equals(action)) { + if (Intent.ACTION_EDIT.equals(action) || Intent.ACTION_VIEW.equals(action)) { // Requested to edit: set that state, and the data being edited. mState = STATE_EDIT; mUri = intent.getData(); @@ -380,65 +379,75 @@ protected void onCreate(Bundle savedInstanceState) { // Load the file into a new note. mFileContent = readFile(FileUriUtils.getFile(mUri)); - } else if (!mUri.getAuthority().equals(NotePad.AUTHORITY)) { + } else if ( ! mUri.getAuthority().equals(NotePad.AUTHORITY)) { // Note a notepad note. Treat slightly differently. // (E.g. a note from OI Shopping List) mState = STATE_EDIT_EXTERNAL_NOTE; } /* - * if (mUri.getScheme().equals("file")) { // Load the file into - * a new note. - * - * mFilename = FileUriUtils.getFilename(mUri); - * - * String text = readFile(FileUriUtils.getFile(mUri)); - * - * if (text == null) { Log.e(TAG, "Error reading file"); - * finish(); return; } - * - * - * - * // Let's check whether the exactly same note already exists - * or not: Cursor c = - * getContentResolver().query(Notes.CONTENT_URI, new String[] - * {Notes._ID}, Notes.NOTE + " = ?", new String[] {text}, null); - * if (c != null && c.getCount() > 0) { // Same note exists - * already: c.moveToFirst(); long id = c.getLong(0); mUri = - * ContentUris.withAppendedId(Notes.CONTENT_URI, id); } else { - * - * // Add new note // Requested to insert: set that state, and - * create a new entry // in the container. mState = - * STATE_INSERT; ContentValues values = new ContentValues(); - * values.put(Notes.NOTE, text); mUri = - * getContentResolver().insert(Notes.CONTENT_URI, values); - * intent.setAction(Intent.ACTION_EDIT); intent.setData(mUri); - * setIntent(intent); - * - * // If we were unable to create a new note, then just finish - * // this activity. A RESULT_CANCELED will be sent back to the - * // original activity if they requested a result. if (mUri == - * null) { Log.e(TAG, "Failed to insert new note into " + - * getIntent().getData()); finish(); return; } - * - * // The new entry was created, so assume all will end well and - * // set the result to be returned. //setResult(RESULT_OK, (new - * Intent()).setAction(mUri.toString())); setResult(RESULT_OK, - * intent); } - * - * } - */ - } else if (Intent.ACTION_INSERT.equals(action) - || Intent.ACTION_SEND.equals(action)) { + if (mUri.getScheme().equals("file")) { + // Load the file into a new note. + + mFilename = FileUriUtils.getFilename(mUri); + + String text = readFile(FileUriUtils.getFile(mUri)); + + if (text == null) { + Log.e(TAG, "Error reading file"); + finish(); + return; + } + + + + // Let's check whether the exactly same note already exists or not: + Cursor c = getContentResolver().query(Notes.CONTENT_URI, + new String[] {Notes._ID}, + Notes.NOTE + " = ?", new String[] {text}, null); + if (c != null && c.getCount() > 0) { + // Same note exists already: + c.moveToFirst(); + long id = c.getLong(0); + mUri = ContentUris.withAppendedId(Notes.CONTENT_URI, id); + } else { + + // Add new note + // Requested to insert: set that state, and create a new entry + // in the container. + mState = STATE_INSERT; + ContentValues values = new ContentValues(); + values.put(Notes.NOTE, text); + mUri = getContentResolver().insert(Notes.CONTENT_URI, values); + intent.setAction(Intent.ACTION_EDIT); + intent.setData(mUri); + setIntent(intent); + + // If we were unable to create a new note, then just finish + // this activity. A RESULT_CANCELED will be sent back to the + // original activity if they requested a result. + if (mUri == null) { + Log.e(TAG, "Failed to insert new note into " + getIntent().getData()); + finish(); + return; + } + + // The new entry was created, so assume all will end well and + // set the result to be returned. + //setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); + setResult(RESULT_OK, intent); + } + + }*/ + } else if (Intent.ACTION_INSERT.equals(action) || Intent.ACTION_SEND.equals(action)) { // Use theme of most recently modified note: ContentValues values = new ContentValues(1); String theme = getMostRecentlyUsedTheme(); values.put(Notes.THEME, theme); - String tags = intent - .getStringExtra(NotepadInternalIntents.EXTRA_TAGS); + String tags = intent.getStringExtra(NotepadInternalIntents.EXTRA_TAGS); values.put(Notes.TAGS, tags); - - if (mText != null) { + + if(mText != null) { values.put(Notes.SELECTION_START, mText.getSelectionStart()); values.put(Notes.SELECTION_END, mText.getSelectionEnd()); } @@ -447,59 +456,54 @@ protected void onCreate(Bundle savedInstanceState) { // in the container. mState = STATE_INSERT; /* - * intent.setAction(Intent.ACTION_EDIT); intent.setData(mUri); - * setIntent(intent); + intent.setAction(Intent.ACTION_EDIT); + intent.setData(mUri); + setIntent(intent); */ - - if (Intent.ACTION_SEND.equals(action)) { - values.put(Notes.NOTE, - getIntent().getStringExtra(Intent.EXTRA_TEXT)); - mUri = getContentResolver().insert(Notes.CONTENT_URI, - values); + + if(Intent.ACTION_SEND.equals(action)) { + values.put(Notes.NOTE, getIntent().getStringExtra(Intent.EXTRA_TEXT)); + mUri = getContentResolver().insert(Notes.CONTENT_URI, values); } else { - mUri = getContentResolver() - .insert(intent.getData(), values); + mUri = getContentResolver().insert(intent.getData(), values); } // If we were unable to create a new note, then just finish - // this activity. A RESULT_CANCELED will be sent back to the + // this activity. A RESULT_CANCELED will be sent back to the // original activity if they requested a result. if (mUri == null) { - Log.e(TAG, "Failed to insert new note into " - + getIntent().getData()); + Log.e(TAG, "Failed to insert new note into " + getIntent().getData()); finish(); return; } // The new entry was created, so assume all will end well and // set the result to be returned. - // setResult(RESULT_OK, (new - // Intent()).setAction(mUri.toString())); + //setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); setResult(RESULT_OK, intent); } else { - // Whoops, unknown action! Bail. + // Whoops, unknown action! Bail. Log.e(TAG, "Unknown action, exiting"); finish(); return; } } - - // setup actionbar - if (mActionBarAvailable) { + + //setup actionbar + if(mActionBarAvailable){ requestWindowFeature(Window.FEATURE_ACTION_BAR); WrapActionBar bar = new WrapActionBar(this); bar.setDisplayHomeAsUpEnabled(true); - // force to show the actionbar on version 14+ - if (Integer.valueOf(android.os.Build.VERSION.SDK) >= 14) { + //force to show the actionbar on version 14+ + if(Integer.valueOf(android.os.Build.VERSION.SDK) >= 14){ bar.setHomeButtonEnabled(true); } - } else { + }else{ requestWindowFeature(Window.FEATURE_RIGHT_ICON); } - - // Set the layout for this activity. You can find it in - // res/layout/note_editor.xml + + // Set the layout for this activity. You can find it in res/layout/note_editor.xml setContentView(R.layout.note_editor); // The text view for our note, identified by its ID in the XML file. @@ -513,77 +517,77 @@ protected void onCreate(Bundle savedInstanceState) { if (mState != STATE_EDIT_NOTE_FROM_SDCARD) { // Check if we load a note from notepad or from some external module - if (mState == STATE_EDIT_EXTERNAL_NOTE) { - // Get all the columns as we don't know which columns are - // supported. + if(mState == STATE_EDIT_EXTERNAL_NOTE){ + // Get all the columns as we don't know which columns are supported. mCursor = managedQuery(mUri, null, null, null, null); - - // Now check which columns are available - List<String> columnNames = Arrays.asList(mCursor - .getColumnNames()); - - if (!columnNames.contains(Notes.NOTE)) { + + //Now check which columns are available + List<String> columnNames = Arrays.asList(mCursor.getColumnNames()); + + if(!columnNames.contains(Notes.NOTE)){ hasNoteColumn = false; } - if (!columnNames.contains(Notes.TAGS)) { + if(!columnNames.contains(Notes.TAGS)){ hasTagsColumn = false; } - if (!columnNames.contains(Notes.ENCRYPTED)) { + if(!columnNames.contains(Notes.ENCRYPTED)){ hasEncryptionColumn = false; } - if (!columnNames.contains(Notes.THEME)) { + if(!columnNames.contains(Notes.THEME)){ hasThemeColumn = false; } - if (!columnNames.contains(Notes.SELECTION_START)) { + if(!columnNames.contains(Notes.COLOR)){ + hasColorColumn = false; + } + if(!columnNames.contains(Notes.SELECTION_START)){ hasSelection_startColumn = false; } - if (!columnNames.contains(Notes.SELECTION_END)) { + if(!columnNames.contains(Notes.SELECTION_END)){ hasSelection_endColumn = false; } - } else { + } + else{ // Get the note! mCursor = managedQuery(mUri, PROJECTION, null, null, null); - - // It's not an external note, so all the columns are available - // in the database - } + + //It's not an external note, so all the columns are available in the database + } } else { mCursor = null; } - - mText.addTextChangedListener(mTextWatcherCharCount); + + mText.addTextChangedListener(mTextWatcherCharCount); } - + /** - * Return intent data when invoked with - * action=android.intent.action.CREATE_SHORTCUT + * Return intent data when invoked with action=android.intent.action.CREATE_SHORTCUT */ private void createShortcut() { - Intent intent = new Intent(Intent.ACTION_INSERT, Notes.CONTENT_URI, - getApplicationContext(), NoteEditor.class); - + Intent intent = new Intent(Intent.ACTION_INSERT, + Notes.CONTENT_URI, getApplicationContext(), NoteEditor.class); + Intent result = new Intent(); result.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); result.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - ShortcutIconResource.fromContext(getApplicationContext(), + ShortcutIconResource.fromContext( + getApplicationContext(), R.drawable.ic_launcher_notepad)); - result.putExtra(Intent.EXTRA_SHORTCUT_NAME, - getString(R.string.new_note)); - + result.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.new_note)); + setResult(RESULT_OK, result); - + finish(); } /** * Returns most recently used theme, or null. - * * @return */ private String getMostRecentlyUsedTheme() { String theme = null; - Cursor c = getContentResolver().query(Notes.CONTENT_URI, - new String[] { Notes.THEME }, null, null, + Cursor c = getContentResolver().query( + Notes.CONTENT_URI, + new String[] {Notes.THEME}, null, null, Notes.MODIFIED_DATE + " DESC"); if (c != null && c.moveToFirst()) { theme = c.getString(0); @@ -594,28 +598,27 @@ private String getMostRecentlyUsedTheme() { private TextWatcher mTextWatcherSdCard = new TextWatcher() { public void afterTextChanged(Editable s) { - // if (debug) Log.d(TAG, "after"); + //if (debug) Log.d(TAG, "after"); mFileContent = s.toString(); updateTitleSdCard(); } public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // if (debug) Log.d(TAG, "before"); + //if (debug) Log.d(TAG, "before"); } public void onTextChanged(CharSequence s, int start, int before, int count) { - // if (debug) Log.d(TAG, "on"); + //if (debug) Log.d(TAG, "on"); } }; - + private TextWatcher mTextWatcherCharCount = new TextWatcher() { - public void afterTextChanged(Editable s) { + public void afterTextChanged(Editable s){ updateCharCount(); } - public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @@ -657,8 +660,8 @@ public String readFile(File file) { } catch (FileNotFoundException e) { Log.e(TAG, "File not found", e); - Toast.makeText(this, R.string.file_not_found, Toast.LENGTH_SHORT) - .show(); + Toast.makeText(this, R.string.file_not_found, + Toast.LENGTH_SHORT).show(); return null; } catch (IOException e) { Log.e(TAG, "File not found", e); @@ -673,11 +676,9 @@ public String readFile(File file) { @Override protected void onResume() { super.onResume(); - if (debug) - Log.d(TAG, "onResume"); + if (debug) Log.d(TAG, "onResume"); - if (debug) - Log.d(TAG, "mDecrypted: " + mDecryptedText); + if (debug) Log.d(TAG, "mDecrypted: " + mDecryptedText); // Set auto-link on or off, based on the current setting. int autoLink = PreferenceActivity.getAutoLinkFromPreference(this); @@ -698,12 +699,10 @@ protected void onResume() { } // Make sure that we don't use the link movement method. - // Instead, we need a blend between the arrow key movement (for regular - // navigation) and + // Instead, we need a blend between the arrow key movement (for regular navigation) and // the link movement (so the user can click on links). mText.setMovementMethod(new ArrowKeyMovementMethod() { - public boolean onTouchEvent(TextView widget, Spannable buffer, - MotionEvent event) { + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { // This block is copied and pasted from LinkMovementMethod's // onTouchEvent (without the part that actually changes the // selection). @@ -723,8 +722,7 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); - ClickableSpan[] link = buffer.getSpans(off, off, - ClickableSpan.class); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { link[0].onClick(widget); @@ -733,8 +731,10 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, } return super.onTouchEvent(widget, buffer, event); - } - }); + } + } + ); + setTheme(loadTheme()); } @@ -742,7 +742,9 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, private void getNoteFromContentProvider() { // If we didn't have any trouble retrieving the data, it is now // time to get at the stuff. - if (mCursor != null && mCursor.requery() && mCursor.moveToFirst()) { + if (mCursor != null + && mCursor.requery() + && mCursor.moveToFirst()) { // Modify our overall title depending on the mode we are running in. if (mState == STATE_EDIT || mState == STATE_EDIT_EXTERNAL_NOTE) { @@ -750,66 +752,72 @@ private void getNoteFromContentProvider() { } else if (mState == STATE_INSERT) { setTitle(getText(R.string.title_create)); } - + // This always has to be available long id = mCursor.getLong(mCursor.getColumnIndex(Notes._ID)); - String note = ""; - - if (mState == STATE_EDIT_EXTERNAL_NOTE) { - // Check if the other columns are available - + String note = ""; + + if(mState == STATE_EDIT_EXTERNAL_NOTE){ + //Check if the other columns are available + // Note - if (hasNoteColumn) { - note = mCursor - .getString(mCursor.getColumnIndex(Notes.NOTE)); - } else { + if(hasNoteColumn){ + note = mCursor.getString(mCursor.getColumnIndex(Notes.NOTE)); + } + else{ note = ""; } - + // Encrypted mEncrypted = isNoteUnencrypted() ? 0 : 1; + + // Color + if(hasColorColumn){ + mColor = mCursor.getInt(mCursor.getColumnIndex(Notes.COLOR)); + setNoteColor(mColor); + } // Theme - if (hasThemeColumn) { - mTheme = mCursor.getString(mCursor - .getColumnIndex(Notes.THEME)); - } else { - note = ""; + if(hasThemeColumn){ + mTheme = mCursor.getString(mCursor.getColumnIndex(Notes.THEME)); } - + else{ + //note = ""; + } + // Selection start - if (hasSelection_startColumn) { - mSelectionStart = mCursor.getInt(mCursor - .getColumnIndex(Notes.SELECTION_START)); - } else { + if(hasSelection_startColumn){ + mSelectionStart = mCursor.getInt(mCursor.getColumnIndex(Notes.SELECTION_START)); + } + else{ mSelectionStart = 0; } - - // Selection end - if (hasSelection_endColumn) { - mSelectionStop = mCursor.getInt(mCursor - .getColumnIndex(Notes.SELECTION_END)); - } else { + + //Selection end + if(hasSelection_endColumn){ + mSelectionStop = mCursor.getInt(mCursor.getColumnIndex(Notes.SELECTION_END)); + } + else{ mSelectionStop = 0; } - } else { + } + else{ // We know for sure all the columns are available note = mCursor.getString(COLUMN_INDEX_NOTE); mEncrypted = mCursor.getLong(COLUMN_INDEX_ENCRYPTED); mTheme = mCursor.getString(COLUMN_INDEX_THEME); mSelectionStart = mCursor.getInt(COLUMN_INDEX_SELECTION_START); mSelectionStop = mCursor.getInt(COLUMN_INDEX_SELECTION_END); + mColor = mCursor.getInt(COLUMN_INDEX_COLOR); } if (mEncrypted == 0) { // Not encrypted - // This is a little tricky: we may be resumed after previously - // being - // paused/stopped. We want to put the new text in the text view, - // but leave the user where they were (retain the cursor - // position - // etc). This version of setText does that for us. + // This is a little tricky: we may be resumed after previously being + // paused/stopped. We want to put the new text in the text view, + // but leave the user where they were (retain the cursor position + // etc). This version of setText does that for us. if (!note.equals(mText.getText().toString())) { mText.setTextKeepState(note); // keep state does not work, so we have to do it manually: @@ -818,25 +826,21 @@ private void getNoteFromContentProvider() { } else { if (mDecryptedText != null) { // Text had already been decrypted, use that: - if (debug) - Log.d(TAG, "set decrypted text as mText: " - + mDecryptedText); + if (debug) Log.d(TAG, "set decrypted text as mText: " + mDecryptedText); mText.setTextKeepState(mDecryptedText); // keep state does not work, so we have to do it manually: mText.setSelection(mSelectionStart, mSelectionStop); if (!mActionBarAvailable) { - setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, - android.R.drawable.ic_lock_idle_lock); + setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, android.R.drawable.ic_lock_idle_lock); } } else { // Decrypt note - if (debug) - Log.d(TAG, "Decrypt note: " + note); + if (debug) Log.d(TAG, "Decrypt note: " + note); // Overwrite mText because it may contain unencrypted note // from savedInstanceState. - // mText.setText(R.string.encrypted); + //mText.setText(R.string.encrypted); Intent i = new Intent(); i.setAction(CryptoIntents.ACTION_DECRYPT); @@ -846,7 +850,8 @@ private void getNoteFromContentProvider() { try { startActivityForResult(i, REQUEST_CODE_DECRYPT); } catch (ActivityNotFoundException e) { - Toast.makeText(this, R.string.decryption_failed, + Toast.makeText(this, + R.string.decryption_failed, Toast.LENGTH_SHORT).show(); Log.e(TAG, "failed to invoke decrypt"); } @@ -854,7 +859,7 @@ private void getNoteFromContentProvider() { } // If we hadn't previously retrieved the original text, do so - // now. This allows the user to revert their changes. + // now. This allows the user to revert their changes. if (mOriginalContent == null) { mOriginalContent = note; } @@ -866,8 +871,7 @@ private void getNoteFromContentProvider() { } private void getNoteFromFile() { - if (debug) - Log.d(TAG, "file: " + mFileContent); + if (debug) Log.d(TAG, "file: " + mFileContent); mText.setTextKeepState(mFileContent); // keep state does not work, so we have to do it manually: @@ -878,7 +882,7 @@ private void getNoteFromFile() { } // If we hadn't previously retrieved the original text, do so - // now. This allows the user to revert their changes. + // now. This allows the user to revert their changes. if (mOriginalContent == null) { mOriginalContent = mFileContent; } @@ -893,12 +897,11 @@ private void updateTitleSdCard() { } String filename = FileUriUtils.getFilename(mUri); setTitle(modified + filename); - // setTitle(getString(R.string.title_edit_file, modified + filename)); - // setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, - // android.R.drawable.ic_menu_save); + //setTitle(getString(R.string.title_edit_file, modified + filename)); + //setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, android.R.drawable.ic_menu_save); } - private void updateCharCount() { + private void updateCharCount(){ boolean charCountVisible = false; String currentTitle = getTitle().toString(); if (currentTitle.startsWith("[")) { @@ -906,8 +909,7 @@ private void updateCharCount() { } if (PreferenceActivity.getCharCountEnabledFromPrefs(this)) { if (charCountVisible) { - setTitle("[" + mText.length() + "]" - + currentTitle.substring(currentTitle.indexOf(" "))); + setTitle("[" + mText.length() + "]" + currentTitle.substring(currentTitle.indexOf(" "))); } else { setTitle("[" + mText.length() + "] " + currentTitle); } @@ -920,9 +922,8 @@ private void updateCharCount() { @Override protected void onSaveInstanceState(Bundle outState) { - if (debug) - Log.d(TAG, "onSaveInstanceState"); - // if (debug) Log.d(TAG, "file content: " + mFileContent); + if (debug) Log.d(TAG, "onSaveInstanceState"); + //if (debug) Log.d(TAG, "file content: " + mFileContent); // Save away the original text, so we still have it if the activity // needs to be killed while paused. @@ -930,9 +931,7 @@ protected void onSaveInstanceState(Bundle outState) { mSelectionStop = mText.getSelectionEnd(); mFileContent = mText.getText().toString(); - if (debug) - Log.d(TAG, "Selection " + mSelectionStart + " - " + mSelectionStop - + " for text : " + mFileContent); + if (debug) Log.d(TAG, "Selection " + mSelectionStart + " - " + mSelectionStop + " for text : " + mFileContent); outState.putString(BUNDLE_ORIGINAL_CONTENT, mOriginalContent); outState.putString(BUNDLE_UNDO_REVERT, mUndoRevert); @@ -949,25 +948,24 @@ protected void onSaveInstanceState(Bundle outState) { @Override protected void onPause() { super.onPause(); - if (debug) - Log.d(TAG, "onPause"); + if (debug) Log.d(TAG, "onPause"); mText.setAutoLinkMask(0); // The user is going somewhere else, so make sure their current - // changes are safely saved away in the provider. We don't need + // changes are safely saved away in the provider. We don't need // to do this if only editing. if (mCursor != null) { mCursor.moveToFirst(); - + if (isNoteUnencrypted()) { String text = mText.getText().toString(); int length = text.length(); // If this activity is finished, and there is no text, then we // do something a little special: simply delete the note entry. - // Note that we do this both for editing and inserting... it + // Note that we do this both for editing and inserting... it // would be reasonable to only do it when inserting. if (isFinishing() && (length == 0) && !mNoteOnly) { setResult(RESULT_CANCELED); @@ -977,23 +975,20 @@ protected void onPause() { } else { ContentValues values = new ContentValues(); - // This stuff is only done when working with a full-fledged - // note. + // This stuff is only done when working with a full-fledged note. if (!mNoteOnly) { String oldText = ""; - Cursor cursor = getContentResolver().query(mUri, - new String[] { "note" }, null, null, null); - if (cursor.moveToFirst()) { + Cursor cursor = getContentResolver().query(mUri, new String[]{"note"}, null, null, null); + if ( cursor.moveToFirst() ) { oldText = cursor.getString(0); } - if (!oldText.equals(text)) { + if ( ! oldText.equals(text) ) { // Bump the modification time to now. - values.put(Notes.MODIFIED_DATE, - System.currentTimeMillis()); + values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); } String title; - if (PreferenceActivity.getMarqueeFromPrefs(this) == false) { + if(PreferenceActivity.getMarqueeFromPrefs(this) == false) { title = ExtractTitle.extractTitle(text); } else { title = text; @@ -1002,25 +997,25 @@ protected void onPause() { } // Write our text back into the provider. - if (hasNoteColumn) { + if(hasNoteColumn){ values.put(Notes.NOTE, text); } - if (hasThemeColumn) { + if(hasThemeColumn){ values.put(Notes.THEME, mTheme); } - if (hasSelection_startColumn) { - values.put(Notes.SELECTION_START, - mText.getSelectionStart()); + if(hasColorColumn){ + values.put(Notes.COLOR, mColor); } - if (hasSelection_endColumn) { - values.put(Notes.SELECTION_END, mText.getSelectionEnd()); + if(hasSelection_startColumn){ + values.put(Notes.SELECTION_START, mText.getSelectionStart()); } + if(hasSelection_endColumn){ + values.put(Notes.SELECTION_END, mText.getSelectionEnd()); + } - // Commit all of our changes to persistent storage. When the - // update completes - // the content provider will notify the cursor of the - // change, which will - // cause the UI to be updated. + // Commit all of our changes to persistent storage. When the update completes + // the content provider will notify the cursor of the change, which will + // cause the UI to be updated. getContentResolver().update(mUri, values, null, null); } } else { @@ -1028,11 +1023,14 @@ protected void onPause() { // Save current theme: ContentValues values = new ContentValues(); - - if (hasThemeColumn) { + + if(hasThemeColumn){ values.put(Notes.THEME, mTheme); } - + if(hasColorColumn){ + values.put(Notes.COLOR, mColor); + } + getContentResolver().update(mUri, values, null, null); if (mDecryptedText != null) { @@ -1042,7 +1040,7 @@ protected void onPause() { encryptNote(false); // Remove displayed note. - // mText.setText(R.string.encrypted); + //mText.setText(R.string.encrypted); } } } @@ -1050,19 +1048,18 @@ protected void onPause() { /** * Encrypt the current note. - * * @param text */ private void encryptNote(boolean encryptTags) { String text = mText.getText().toString(); String title; - if (PreferenceActivity.getMarqueeFromPrefs(this) == false) { + if(PreferenceActivity.getMarqueeFromPrefs(this) == false) { title = ExtractTitle.extractTitle(text); } else { title = text; } String tags = getTags(); - // Log.i(TAG, "encrypt tags: " + tags); + //Log.i(TAG, "encrypt tags: " + tags); boolean isNoteEncrypted = !isNoteUnencrypted(); @@ -1070,15 +1067,12 @@ private void encryptNote(boolean encryptTags) { tags = null; } - if (debug) - Log.d(TAG, "encrypt note: " + text); + if (debug) Log.d(TAG, "encrypt note: " + text); if (EncryptActivity.getPendingEncryptActivities() == 0) { Intent i = new Intent(this, EncryptActivity.class); - i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, - CryptoIntents.ACTION_ENCRYPT); - i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, - EncryptActivity.getCryptoStringArray(text, title, tags)); + i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, CryptoIntents.ACTION_ENCRYPT); + i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, EncryptActivity.getCryptoStringArray(text, title, tags)); i.putExtra(PrivateNotePadIntents.EXTRA_URI, mUri.toString()); if (text.equals(mOriginalContent) && isNoteEncrypted) { // No need to encrypt, content was not modified. @@ -1087,11 +1081,9 @@ private void encryptNote(boolean encryptTags) { startActivity(i); // Remove knowledge of the decrypted note. - // If encryption fails because one has been locked out, (another) - // user + // If encryption fails because one has been locked out, (another) user // should not be able to see note again from cache. - if (debug) - Log.d(TAG, "using static decrypted text: " + text); + if (debug) Log.d(TAG, "using static decrypted text: " + text); sDecryptedText = text; if (isNoteEncrypted) { // Already encrypted @@ -1105,29 +1097,26 @@ private void encryptNote(boolean encryptTags) { EncryptActivity.confirmEncryptActivityCalled(); } else { // encrypt already called - if (debug) - Log.d(TAG, "encrypt already called"); + if (debug) Log.d(TAG, "encrypt already called"); } } public static void deleteStaticDecryptedText() { - if (debug) - Log.d(TAG, "deleting decrypted text: " + sDecryptedText); + if (debug) Log.d(TAG, "deleting decrypted text: " + sDecryptedText); sDecryptedText = null; } /** * Unencrypt the current note. - * * @param text */ private void unencryptNote() { String text = mText.getText().toString(); String title = ExtractTitle.extractTitle(text); String tags = getTags(); - // Log.i(TAG, "unencrypt tags: " + tags); + //Log.i(TAG, "unencrypt tags: " + tags); ContentValues values = new ContentValues(); values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); @@ -1142,25 +1131,22 @@ private void unencryptNote() { setFeatureDrawable(Window.FEATURE_RIGHT_ICON, null); } - // Small trick: Tags have not been converted properly yet. Let's do it - // now: + // Small trick: Tags have not been converted properly yet. Let's do it now: Intent i = new Intent(this, EncryptActivity.class); - i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, - CryptoIntents.ACTION_DECRYPT); - i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, - EncryptActivity.getCryptoStringArray(null, null, tags)); + i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, CryptoIntents.ACTION_DECRYPT); + i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, EncryptActivity.getCryptoStringArray(null, null, tags)); i.putExtra(PrivateNotePadIntents.EXTRA_URI, mUri.toString()); startActivity(i); } private String getTags() { String tags; - - // Check if there is a tags column in the database + + //Check if there is a tags column in the database int index; - if ((index = mCursor.getColumnIndex(Notes.TAGS)) != -1) { - tags = mCursor.getString(index); - } else { + if((index = mCursor.getColumnIndex(Notes.TAGS)) != -1){ + tags = mCursor.getString(index); } + else{ tags = ""; } @@ -1177,67 +1163,79 @@ public boolean onCreateOptionsMenu(Menu menu) { // Build the menus that are shown when editing. - // if (!mOriginalContent.equals(mText.getText().toString())) { + //if (!mOriginalContent.equals(mText.getText().toString())) { - menu.add(0, MENU_REVERT, 0, R.string.menu_revert).setShortcut('0', 'r') - .setIcon(android.R.drawable.ic_menu_revert); - // } + menu.add(0, MENU_REVERT, 0, R.string.menu_revert) + .setShortcut('0', 'r') + .setIcon(android.R.drawable.ic_menu_revert); + //} menu.add(1, MENU_ENCRYPT, 0, R.string.menu_encrypt) - .setShortcut('1', 'e').setIcon(android.R.drawable.ic_lock_lock); // TODO: - // better - // icon + .setShortcut('1', 'e') + .setIcon(android.R.drawable.ic_lock_lock); // TODO: better icon menu.add(1, MENU_UNENCRYPT, 0, R.string.menu_undo_encryption) - .setShortcut('1', 'e').setIcon(android.R.drawable.ic_lock_lock); // TODO: - // better - // icon + .setShortcut('1', 'e') + .setIcon(android.R.drawable.ic_lock_lock); // TODO: better icon MenuItem item = menu.add(1, MENU_DELETE, 0, R.string.menu_delete); item.setIcon(android.R.drawable.ic_menu_delete); + + menu.add(2, MENU_IMPORT, 0, R.string.menu_import) + .setShortcut('1', 'i') + .setIcon(android.R.drawable.ic_menu_add); - menu.add(2, MENU_IMPORT, 0, R.string.menu_import).setShortcut('1', 'i') - .setIcon(android.R.drawable.ic_menu_add); - - menu.add(2, MENU_SAVE, 0, R.string.menu_save).setShortcut('2', 's') - .setIcon(android.R.drawable.ic_menu_save); + menu.add(2, MENU_SAVE, 0, R.string.menu_save) + .setShortcut('2', 's') + .setIcon(android.R.drawable.ic_menu_save); menu.add(2, MENU_SAVE_AS, 0, R.string.menu_save_as) - .setShortcut('3', 'w').setIcon(android.R.drawable.ic_menu_save); + .setShortcut('3', 'w') + .setIcon(android.R.drawable.ic_menu_save); - menu.add(3, MENU_THEME, 0, R.string.menu_theme) - .setIcon(android.R.drawable.ic_menu_manage) - .setShortcut('4', 't'); + menu.add(3, MENU_THEME, 0, R.string.menu_theme).setIcon( + android.R.drawable.ic_menu_manage).setShortcut('4', 't'); - menu.add(3, MENU_SETTINGS, 0, R.string.settings) - .setIcon(android.R.drawable.ic_menu_preferences) - .setShortcut('9', 'p'); + menu.add(3, MENU_SETTINGS, 0, R.string.settings).setIcon( + android.R.drawable.ic_menu_preferences).setShortcut('9', 'p'); - item = menu.add(4, MENU_SEND, 0, R.string.menu_share); + item = menu.add(4, MENU_COLOR, 0, R.string.menu_color); + item.setIcon( R.drawable.notes_btn_changecolors ); + if(mActionBarAvailable){ + WrapActionBar.showIfRoom(item); + } + item = menu.add(5, MENU_SEND, 0, R.string.menu_share); item.setIcon(android.R.drawable.ic_menu_share); - if (mActionBarAvailable) { + if(mActionBarAvailable){ WrapActionBar.showIfRoom(item); } - + menu.add(5, MENU_WORD_COUNT, 0, R.string.menu_word_count); - + /* - * if (mState == STATE_EDIT) { - * - * menu.add(0, REVERT_ID, 0, R.string.menu_revert) .setShortcut('0', - * 'r') .setIcon(android.R.drawable.ic_menu_revert); - * - * if (!mNoteOnly) { menu.add(1, DELETE_ID, 0, R.string.menu_delete) - * .setShortcut('1', 'd') .setIcon(android.R.drawable.ic_menu_delete); } - * - * // Build the menus that are shown when inserting. } else { - * menu.add(1, DISCARD_ID, 0, R.string.menu_discard) .setShortcut('0', - * 'd') .setIcon(android.R.drawable.ic_menu_delete); } + if (mState == STATE_EDIT) { + + menu.add(0, REVERT_ID, 0, R.string.menu_revert) + .setShortcut('0', 'r') + .setIcon(android.R.drawable.ic_menu_revert); + + if (!mNoteOnly) { + menu.add(1, DELETE_ID, 0, R.string.menu_delete) + .setShortcut('1', 'd') + .setIcon(android.R.drawable.ic_menu_delete); + } + + // Build the menus that are shown when inserting. + } else { + menu.add(1, DISCARD_ID, 0, R.string.menu_discard) + .setShortcut('0', 'd') + .setIcon(android.R.drawable.ic_menu_delete); + } */ // If we are working on a full note, then append to the // menu items for any other activities that can do stuff with it - // as well. This does a query on the system for any activities that + // as well. This does a query on the system for any activities that // implement the ALTERNATIVE_ACTION for our data, adding a menu item // for each one that is found. if (!mNoteOnly) { @@ -1246,16 +1244,13 @@ public boolean onCreateOptionsMenu(Menu menu) { // a new note. Intent intent = new Intent(null, mUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); - // menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, - // new ComponentName(this, NoteEditor.class), null, intent, 0, - // null); + //menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, + // new ComponentName(this, NoteEditor.class), null, intent, 0, null); // Workaround to add icons: - MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons( - this, menu); + MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, menu); menu2.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, - new ComponentName(this, NoteEditor.class), null, intent, 0, - null); + new ComponentName(this, NoteEditor.class), null, intent, 0, null); // Add menu items for category CATEGORY_TEXT_SELECTION_ALTERNATIVE intent = new Intent(); // Don't pass data for this intent @@ -1263,8 +1258,7 @@ public boolean onCreateOptionsMenu(Menu menu) { intent.setType("text/plain"); // Workaround to add icons: menu2.addIntentOptions(GROUP_ID_TEXT_SELECTION_ALTERNATIVE, 0, 0, - new ComponentName(this, NoteEditor.class), null, intent, 0, - null); + new ComponentName(this, NoteEditor.class), null, intent, 0, null); } @@ -1275,11 +1269,11 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) { // Show "revert" menu item only if content has changed. - boolean contentChanged = !mOriginalContent.equals(mText.getText() - .toString()); + boolean contentChanged = !mOriginalContent.equals(mText.getText().toString()); boolean isNoteUnencrypted = isNoteUnencrypted(); + // Show comands on the URI only if the note is not encrypted menu.setGroupVisible(Menu.CATEGORY_ALTERNATIVE, isNoteUnencrypted); @@ -1314,11 +1308,11 @@ public boolean onPrepareOptionsMenu(Menu menu) { private boolean isNoteUnencrypted() { long encrypted = 0; if (mCursor != null && mCursor.moveToFirst()) { - // Check if the column Notes.ENCRYPTED exists - if (hasEncryptionColumn) { - encrypted = mCursor.getInt(mCursor - .getColumnIndex(Notes.ENCRYPTED)); - } else { + //Check if the column Notes.ENCRYPTED exists + if(hasEncryptionColumn){ + encrypted = mCursor.getInt(mCursor.getColumnIndex(Notes.ENCRYPTED)); + } + else{ encrypted = 0; } } @@ -1330,47 +1324,50 @@ private boolean isNoteUnencrypted() { public boolean onOptionsItemSelected(MenuItem item) { // Handle all of the possible menu actions. switch (item.getItemId()) { - case android.R.id.home: - Intent intent = new Intent(this, NotesList.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - break; - case MENU_DELETE: - deleteNoteWithConfirm(); - break; - case MENU_DISCARD: - revertNote(); - break; - case MENU_REVERT: - revertNote(); - break; - case MENU_ENCRYPT: - encryptNote(true); - break; - case MENU_UNENCRYPT: - unencryptNote(); - break; - case MENU_IMPORT: - importNote(); - break; - case MENU_SAVE: - saveNote(); - break; - case MENU_SAVE_AS: - saveAsNote(); - break; - case MENU_THEME: - setThemeSettings(); - return true; - case MENU_SETTINGS: - showNotesListSettings(); - return true; - case MENU_SEND: - shareNote(); - return true; - case MENU_WORD_COUNT: - showWordCount(); - break; + case android.R.id.home: + Intent intent = new Intent(this, NotesList.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + break; + case MENU_DELETE: + deleteNoteWithConfirm(); + break; + case MENU_DISCARD: + revertNote(); + break; + case MENU_REVERT: + revertNote(); + break; + case MENU_ENCRYPT: + encryptNote(true); + break; + case MENU_UNENCRYPT: + unencryptNote(); + break; + case MENU_IMPORT: + importNote(); + break; + case MENU_SAVE: + saveNote(); + break; + case MENU_SAVE_AS: + saveAsNote(); + break; + case MENU_THEME: + setThemeSettings(); + return true; + case MENU_SETTINGS: + showNotesListSettings(); + return true; + case MENU_SEND: + shareNote(); + return true; + case MENU_COLOR: + setColor(); + return true; + case MENU_WORD_COUNT: + showWordCount(); + break; } if (item.getGroupId() == GROUP_ID_TEXT_SELECTION_ALTERNATIVE) { // Process manually: @@ -1383,19 +1380,75 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } + private void setColor() { + LinearLayout color = (LinearLayout) findViewById(R.id.editor_color); + ImageView color_yellow = (ImageView) findViewById(R.id.editor_color_yellow); + ImageView color_pink = (ImageView) findViewById(R.id.editor_color_pink); + ImageView color_blue = (ImageView) findViewById(R.id.editor_color_blue); + ImageView color_green = (ImageView) findViewById(R.id.editor_color_green); + ImageView color_gray = (ImageView) findViewById(R.id.editor_color_gray); + + color_yellow.setOnClickListener(colorListener); + color_pink.setOnClickListener(colorListener); + color_blue.setOnClickListener(colorListener); + color_green.setOnClickListener(colorListener); + color_gray.setOnClickListener(colorListener); + + color.setVisibility(View.VISIBLE); + } + + OnClickListener colorListener = new OnClickListener() { + @Override + public void onClick(View v) { + // TODO Auto-generated method stub + switch (v.getId()) { + case R.id.editor_color_yellow: + setNoteColor((int)R.color.lightYellow); + break; + case R.id.editor_color_pink: + setNoteColor((int)R.color.lightPink); + break; + case R.id.editor_color_blue: + setNoteColor((int)R.color.lightBabyBlue); + break; + case R.id.editor_color_green: + setNoteColor((int)R.color.lightGreen); + break; + case R.id.editor_color_gray: + setNoteColor((int)R.color.lightGray); + break; + default: + break; + } + } + }; + private void shareNote() { String content = mText.getText().toString(); String title = ExtractTitle.extractTitle(content); SendNote.sendNote(this, title, content); } + protected void setNoteColor(int color) { + Resources res = getResources(); + LinearLayout c = (LinearLayout) findViewById(R.id.editor_color); + c.setVisibility(View.GONE); + mText.setBackgroundDrawable(res.getDrawable(color)); + + if (color == mColor) + return; + mColor = color; + ContentValues values = new ContentValues(); + values.put(Notes.COLOR, mColor); + getContentResolver().update(mUri, values, null, null); + } + private void deleteNoteWithConfirm() { showDialog(DIALOG_DELETE); } /** * Modifies an activity to pass along the currently selected text. - * * @param intent */ private void startTextSelectionActivity(Intent intent) { @@ -1405,23 +1458,18 @@ private void startTextSelectionActivity(Intent intent) { int start = mText.getSelectionStart(); int end = mText.getSelectionEnd(); - // if (debug) Log.i(TAG, "len: " + text.length() + ", start: " + start + - // ", end: " + end); + //if (debug) Log.i(TAG, "len: " + text.length() + ", start: " + start + ", end: " + end); if (end < start) { int swap = end; end = start; start = swap; } - newIntent.putExtra(NotepadIntents.EXTRA_TEXT, - text.substring(start, end)); - newIntent.putExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION, - text.substring(0, start)); - newIntent.putExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION, - text.substring(end)); + newIntent.putExtra(NotepadIntents.EXTRA_TEXT, text.substring(start, end)); + newIntent.putExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION, text.substring(0, start)); + newIntent.putExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION, text.substring(end)); - startActivityForResult(newIntent, - REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE); + startActivityForResult(newIntent, REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE); } /** @@ -1431,7 +1479,7 @@ private final void revertNote() { if (mCursor != null) { String tmp = mText.getText().toString(); mText.setAutoLinkMask(0); - if (!tmp.equals(mOriginalContent)) { + if (! tmp.equals(mOriginalContent)) { // revert to original content mText.setTextKeepState(mOriginalContent); mUndoRevert = tmp; @@ -1443,13 +1491,13 @@ private final void revertNote() { int autolink = PreferenceActivity.getAutoLinkFromPreference(this); mText.setAutoLinkMask(autolink); } - // mCursor.requery(); - // setResult(RESULT_CANCELED); - // finish(); + //mCursor.requery(); + //setResult(RESULT_CANCELED); + //finish(); } /** - * Take care of deleting a note. Simply deletes the entry. + * Take care of deleting a note. Simply deletes the entry. */ private final void deleteNote() { if (mCursor != null) { @@ -1459,19 +1507,22 @@ private final void deleteNote() { mText.setText(""); } } - /* - * private final void discardNote() { //if (mCursor != null) { // - * mCursor.close(); // mCursor = null; // getContentResolver().delete(mUri, - * null, null); // mText.setText(""); //} mOriginalContent = - * mText.getText().toString(); mText.setText(""); } + private final void discardNote() { + //if (mCursor != null) { + // mCursor.close(); + // mCursor = null; + // getContentResolver().delete(mUri, null, null); + // mText.setText(""); + //} + mOriginalContent = mText.getText().toString(); + mText.setText(""); + } */ private void applyInsertText() { - if (mApplyTextBefore != null || mApplyText != null - || mApplyTextAfter != null) { - // Need to apply insert text from previous - // TEXT_SELECTION_ALTERNATIVE + if (mApplyTextBefore != null || mApplyText != null || mApplyTextAfter != null) { + // Need to apply insert text from previous TEXT_SELECTION_ALTERNATIVE insertAtPoint(mApplyTextBefore, mApplyText, mApplyTextAfter); @@ -1483,17 +1534,16 @@ private void applyInsertText() { } /** - * Insert textToInsert at current position. Optionally, if textBefore or - * textAfter are non-null, replace the text before or after the current - * selection. + * Insert textToInsert at current position. + * Optionally, if textBefore or textAfter are non-null, + * replace the text before or after the current selection. * * @author isaac * @author Peli */ - private void insertAtPoint(String textBefore, String textToInsert, - String textAfter) { + private void insertAtPoint (String textBefore, String textToInsert, String textAfter) { String originalText = mText.getText().toString(); - int startPos = mText.getSelectionStart(); + int startPos = mText.getSelectionStart(); int endPos = mText.getSelectionEnd(); if (mDecryptedText != null) { // Treat encrypted text: @@ -1503,7 +1553,7 @@ private void insertAtPoint(String textBefore, String textToInsert, } int newStartPos = startPos; int newEndPos = endPos; - ContentValues values = new ContentValues(); + ContentValues values = new ContentValues(); String newNote = ""; StringBuffer sb = new StringBuffer(); if (textBefore != null) { @@ -1534,33 +1584,31 @@ private void insertAtPoint(String textBefore, String textToInsert, } else if (mDecryptedText != null) { mDecryptedText = newNote; } else { - // This stuff is only done when working with a full-fledged note. - if (!mNoteOnly) { - // Bump the modification time to now. - values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); + // This stuff is only done when working with a full-fledged note. + if (!mNoteOnly) { + // Bump the modification time to now. + values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); String title; - if (PreferenceActivity.getMarqueeFromPrefs(this) == false) { + if(PreferenceActivity.getMarqueeFromPrefs(this) == false) { title = ExtractTitle.extractTitle(newNote); } else { title = newNote; } - values.put(Notes.TITLE, title); - } + values.put(Notes.TITLE, title); + } // Write our text back into the provider. values.put(Notes.NOTE, newNote); - // Commit all of our changes to persistent storage. When the update - // completes - // the content provider will notify the cursor of the change, which - // will - // cause the UI to be updated. + // Commit all of our changes to persistent storage. When the update completes + // the content provider will notify the cursor of the change, which will + // cause the UI to be updated. getContentResolver().update(mUri, values, null, null); } - // ijones: notification doesn't seem to trigger for some reason :( + //ijones: notification doesn't seem to trigger for some reason :( mText.setTextKeepState(newNote); // Adjust cursor position according to new length: mText.setSelection(newStartPos, newEndPos); - } + } private void importNote() { // Load the file into a new note. @@ -1570,9 +1618,9 @@ private void importNote() { Uri newUri = null; // Let's check whether the exactly same note already exists or not: - Cursor c = getContentResolver().query(Notes.CONTENT_URI, - new String[] { Notes._ID }, Notes.NOTE + " = ?", - new String[] { mFileContent }, null); + Cursor c = getContentResolver().query(Notes.CONTENT_URI, + new String[] {Notes._ID}, + Notes.NOTE + " = ?", new String[] {mFileContent}, null); if (c != null && c.moveToFirst()) { // Same note exists already: long id = c.getLong(0); @@ -1582,14 +1630,15 @@ private void importNote() { // Add new note // Requested to insert: set that state, and create a new entry // in the container. - // mState = STATE_INSERT; + //mState = STATE_INSERT; ContentValues values = new ContentValues(); values.put(Notes.NOTE, mFileContent); values.put(Notes.THEME, mTheme); newUri = getContentResolver().insert(Notes.CONTENT_URI, values); + // If we were unable to create a new note, then just finish - // this activity. A RESULT_CANCELED will be sent back to the + // this activity. A RESULT_CANCELED will be sent back to the // original activity if they requested a result. if (newUri == null) { Log.e(TAG, "Failed to insert new note."); @@ -1599,10 +1648,11 @@ private void importNote() { // The new entry was created, so assume all will end well and // set the result to be returned. - // setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); - // setResult(RESULT_OK, intent); + //setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); + //setResult(RESULT_OK, intent); } + // Start a new editor: Intent intent = new Intent(); intent.setAction(Intent.ACTION_EDIT); @@ -1647,21 +1697,20 @@ void setThemeSettings() { protected Dialog onCreateDialog(int id) { switch (id) { - case DIALOG_UNSAVED_CHANGES: - return getUnsavedChangesWarningDialog(); + case DIALOG_UNSAVED_CHANGES: + return getUnsavedChangesWarningDialog(); - case DIALOG_THEME: - return new ThemeDialog(this, this); + case DIALOG_THEME: + return new ThemeDialog(this, this); - case DIALOG_DELETE: - return new DeleteConfirmationDialog(this, - new DialogInterface.OnClickListener() { + case DIALOG_DELETE: + return new DeleteConfirmationDialog(this, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface arg0, int arg1) { - deleteNote(); - finish(); - } - }).create(); + public void onClick(DialogInterface arg0, int arg1) { + deleteNote(); + finish(); + } + }).create(); } return null; } @@ -1684,22 +1733,21 @@ public void onSetThemeForAll(String theme) { /** * Set theme for all lists. - * * @param context * @param theme */ public static void setThemeForAll(Context context, String theme) { ContentValues values = new ContentValues(); values.put(Notes.THEME, theme); - context.getContentResolver().update(Notes.CONTENT_URI, values, null, - null); + context.getContentResolver().update( + Notes.CONTENT_URI, values, null, null); } /** * Loads the theme settings for the currently selected theme. * - * Up to version 1.2.1, only one of 3 hardcoded themes are available. These - * are stored in 'skin_background' as '1', '2', or '3'. + * Up to version 1.2.1, only one of 3 hardcoded themes are available. These are stored + * in 'skin_background' as '1', '2', or '3'. * * Starting in 1.2.2, also themes of other packages are allowed. * @@ -1708,23 +1756,30 @@ public static void setThemeForAll(Context context, String theme) { public String loadTheme() { return mTheme; /* - * if (mCursor != null && mCursor.moveToFirst()) { // mCursorListFilter - * has been set to correct position // by calling getSelectedListId(), - * // so we can read out further elements: String skinBackground = - * mCursor .getString(COLUMN_INDEX_THEME); - * - * return skinBackground; } else { return null; } + if (mCursor != null && mCursor.moveToFirst()) { + // mCursorListFilter has been set to correct position + // by calling getSelectedListId(), + // so we can read out further elements: + String skinBackground = mCursor + .getString(COLUMN_INDEX_THEME); + + return skinBackground; + } else { + return null; + } */ } public void saveTheme(String theme) { mTheme = theme; /* - * // Save theme only for content Uris with NotePad authority. // Don't - * save anything for file:// uri. if (mUri != null && - * mUri.getAuthority().equals(NotePad.AUTHORITY)) { ContentValues values - * = new ContentValues(); values.put(Notes.THEME, theme); - * getContentResolver().update(mUri, values, null, null); } + // Save theme only for content Uris with NotePad authority. + // Don't save anything for file:// uri. + if (mUri != null && mUri.getAuthority().equals(NotePad.AUTHORITY)) { + ContentValues values = new ContentValues(); + values.put(Notes.THEME, theme); + getContentResolver().update(mUri, values, null, null); + } */ } @@ -1760,8 +1815,7 @@ private void setLocalStyle(int styleResId, int size) { private boolean setRemoteStyle(String styleName, int size) { if (TextUtils.isEmpty(styleName)) { - if (debug) - Log.e(TAG, "Empty style name: " + styleName); + if (debug) Log.e(TAG, "Empty style name: " + styleName); return false; } @@ -1778,16 +1832,14 @@ private boolean setRemoteStyle(String styleName, int size) { try { c = createPackageContext(packageName, 0); } catch (NameNotFoundException e) { - Log.e(TAG, "Package for style not found: " + packageName + ", " - + styleName); + Log.e(TAG, "Package for style not found: " + packageName + ", " + styleName); return false; } Resources res = c.getResources(); int themeid = res.getIdentifier(styleName, null, null); - if (debug) - Log.d(TAG, "Retrieving theme: " + styleName + ", " + themeid); + if (debug) Log.d(TAG, "Retrieving theme: " + styleName + ", " + themeid); if (themeid == 0) { Log.e(TAG, "Theme name not found: " + styleName); @@ -1798,43 +1850,33 @@ private boolean setRemoteStyle(String styleName, int size) { ThemeAttributes ta = new ThemeAttributes(c, packageName, themeid); mTextTypeface = ta.getString(ThemeNotepad.textTypeface); - if (debug) - Log.d(TAG, "textTypeface: " + mTextTypeface); + if (debug) Log.d(TAG, "textTypeface: " + mTextTypeface); mCurrentTypeface = null; // Look for special cases: if ("monospace".equals(mTextTypeface)) { - mCurrentTypeface = Typeface.create(Typeface.MONOSPACE, - Typeface.NORMAL); + mCurrentTypeface = Typeface.create(Typeface.MONOSPACE, Typeface.NORMAL); } else if ("sans".equals(mTextTypeface)) { - mCurrentTypeface = Typeface.create(Typeface.SANS_SERIF, - Typeface.NORMAL); + mCurrentTypeface = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); } else if ("serif".equals(mTextTypeface)) { - mCurrentTypeface = Typeface.create(Typeface.SERIF, - Typeface.NORMAL); + mCurrentTypeface = Typeface.create(Typeface.SERIF, Typeface.NORMAL); } else if (!TextUtils.isEmpty(mTextTypeface)) { try { - if (debug) - Log.d(TAG, "Reading typeface: package: " + packageName - + ", typeface: " + mTextTypeface); - Resources remoteRes = pm - .getResourcesForApplication(packageName); - mCurrentTypeface = Typeface.createFromAsset( - remoteRes.getAssets(), mTextTypeface); - if (debug) - Log.d(TAG, "Result: " + mCurrentTypeface); + if (debug) Log.d(TAG, "Reading typeface: package: " + packageName + ", typeface: " + mTextTypeface); + Resources remoteRes = pm.getResourcesForApplication(packageName); + mCurrentTypeface = Typeface.createFromAsset(remoteRes.getAssets(), + mTextTypeface); + if (debug) Log.d(TAG, "Result: " + mCurrentTypeface); } catch (NameNotFoundException e) { Log.e(TAG, "Package not found for Typeface", e); } } - mTextUpperCaseFont = ta.getBoolean(ThemeNotepad.textUpperCaseFont, - false); + mTextUpperCaseFont = ta.getBoolean(ThemeNotepad.textUpperCaseFont, false); - mTextColor = ta.getColor(ThemeNotepad.textColor, - android.R.color.white); + mTextColor = ta.getColor(ThemeNotepad.textColor, android.R.color.white); if (debug) { Log.d(TAG, "textColor: " + mTextColor); @@ -1849,35 +1891,25 @@ private boolean setRemoteStyle(String styleName, int size) { } else { mTextSize = getTextSizeLarge(ta); } - if (debug) - Log.d(TAG, "textSize: " + mTextSize); + if (debug) Log.d(TAG, "textSize: " + mTextSize); if (mText != null) { - mBackgroundPadding = ta.getDimensionPixelOffset( - ThemeNotepad.backgroundPadding, -1); - int backgroundPaddingLeft = ta.getDimensionPixelOffset( - ThemeNotepad.backgroundPaddingLeft, mBackgroundPadding); - int backgroundPaddingTop = ta.getDimensionPixelOffset( - ThemeNotepad.backgroundPaddingTop, mBackgroundPadding); - int backgroundPaddingRight = ta - .getDimensionPixelOffset( - ThemeNotepad.backgroundPaddingRight, - mBackgroundPadding); - int backgroundPaddingBottom = ta.getDimensionPixelOffset( - ThemeNotepad.backgroundPaddingBottom, - mBackgroundPadding); + mBackgroundPadding = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPadding, -1); + int backgroundPaddingLeft = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingLeft, mBackgroundPadding); + int backgroundPaddingTop = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingTop, mBackgroundPadding); + int backgroundPaddingRight = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingRight, mBackgroundPadding); + int backgroundPaddingBottom = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingBottom, mBackgroundPadding); if (debug) { - Log.d(TAG, "Padding: " + mBackgroundPadding + "; " - + backgroundPaddingLeft + "; " - + backgroundPaddingTop + "; " - + backgroundPaddingRight + "; " - + backgroundPaddingBottom + "; "); + Log.d(TAG, "Padding: " + mBackgroundPadding + "; " + + backgroundPaddingLeft + "; " + + backgroundPaddingTop + "; " + + backgroundPaddingRight + "; " + + backgroundPaddingBottom + "; "); } try { - Resources remoteRes = pm - .getResourcesForApplication(packageName); + Resources remoteRes = pm.getResourcesForApplication(packageName); int resid = ta.getResourceId(ThemeNotepad.background, 0); if (resid != 0) { Drawable d = remoteRes.getDrawable(resid); @@ -1885,6 +1917,7 @@ private boolean setRemoteStyle(String styleName, int size) { } else { // remove background mText.setBackgroundResource(0); + setNoteColor(mColor); } } catch (NameNotFoundException e) { Log.e(TAG, "Package not found for Theme background.", e); @@ -1893,24 +1926,23 @@ private boolean setRemoteStyle(String styleName, int size) { } // Apply padding - if (mBackgroundPadding >= 0 || backgroundPaddingLeft >= 0 - || backgroundPaddingTop >= 0 - || backgroundPaddingRight >= 0 - || backgroundPaddingBottom >= 0) { - mText.setPadding(backgroundPaddingLeft, - backgroundPaddingTop, backgroundPaddingRight, + if (mBackgroundPadding >=0 + || backgroundPaddingLeft >= 0 || backgroundPaddingTop >= 0 || + backgroundPaddingRight >= 0 || backgroundPaddingBottom >= 0){ + mText.setPadding(backgroundPaddingLeft, + backgroundPaddingTop, + backgroundPaddingRight, backgroundPaddingBottom); } else { // 9-patches do the padding automatically - // todo clear padding + // todo clear padding } } mLinesMode = ta.getInteger(ThemeNotepad.lineMode, 2); mLinesColor = ta.getColor(ThemeNotepad.lineColor, 0xFF000080); - if (debug) - Log.d(TAG, "line color: " + mLinesColor); + if (debug) Log.d(TAG, "line color: " + mLinesColor); return true; @@ -1928,35 +1960,38 @@ private boolean setRemoteStyle(String styleName, int size) { } private float getTextSizeTiny(ThemeAttributes ta) { - float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeTiny, -1); + float size = ta + .getDimensionPixelOffset(ThemeNotepad.textSizeTiny, -1); if (size == -1) { // Try to obtain from small: - size = (12f / 18f) * getTextSizeSmall(ta); + size = (12f/18f) * getTextSizeSmall(ta); } return size; } private float getTextSizeSmall(ThemeAttributes ta) { - float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeSmall, -1); + float size = ta + .getDimensionPixelOffset(ThemeNotepad.textSizeSmall, -1); if (size == -1) { // Try to obtain from small: - size = (18f / 23f) * getTextSizeMedium(ta); + size = (18f/23f) * getTextSizeMedium(ta); } return size; } private float getTextSizeMedium(ThemeAttributes ta) { final float scale = getResources().getDisplayMetrics().scaledDensity; - float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeMedium, - (int) (23 * scale + 0.5f)); + float size = ta + .getDimensionPixelOffset(ThemeNotepad.textSizeMedium, (int) (23 * scale + 0.5f)); return size; } private float getTextSizeLarge(ThemeAttributes ta) { - float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeLarge, -1); + float size = ta + .getDimensionPixelOffset(ThemeNotepad.textSizeLarge, -1); if (size == -1) { // Try to obtain from small: - size = (28f / 23f) * getTextSizeMedium(ta); + size = (28f/23f) * getTextSizeMedium(ta); } return size; } @@ -1967,12 +2002,10 @@ private void applyTheme() { mText.setTextColor(mTextColor); if (mTextUpperCaseFont) { - // Turn off autolinkmask, because it is not compatible with - // transformationmethod. + // Turn off autolinkmask, because it is not compatible with transformationmethod. mText.setAutoLinkMask(0); - mText.setTransformationMethod(UpperCaseTransformationMethod - .getInstance()); + mText.setTransformationMethod(UpperCaseTransformationMethod.getInstance()); } else { mText.setTransformationMethod(null); @@ -1989,7 +2022,7 @@ private void showNotesListSettings() { startActivity(new Intent(this, PreferenceActivity.class)); } - private void showWordCount() { + private void showWordCount(){ String text = mText.getText().toString(); int number_of_words = text.split("\\s+").length; if (TextUtils.isEmpty(text)) { @@ -1997,9 +2030,9 @@ private void showWordCount() { // so in this case we set it manually number_of_words = 0; } - AlertDialog.Builder wordCountAlert = new AlertDialog.Builder(this); - wordCountAlert.setMessage(getResources().getQuantityString( - R.plurals.word_count, number_of_words, number_of_words)); + AlertDialog.Builder wordCountAlert = new AlertDialog.Builder(this); + wordCountAlert.setMessage(getResources().getQuantityString(R.plurals.word_count, + number_of_words, number_of_words)); wordCountAlert.setTitle(R.string.menu_word_count); wordCountAlert.setPositiveButton(R.string.ok, null); wordCountAlert.setCancelable(false); @@ -2008,33 +2041,34 @@ private void showWordCount() { Dialog getUnsavedChangesWarningDialog() { return new AlertDialog.Builder(this) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.warning_unsaved_changes_title) - .setMessage(R.string.warning_unsaved_changes_message) - .setPositiveButton(R.string.button_save, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - // Save - saveNote(); - finish(); - } - }) - .setNeutralButton(R.string.button_dont_save, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - // Don't save - finish(); - } - }) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - // Cancel - } - }).create(); + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.warning_unsaved_changes_title) + .setMessage(R.string.warning_unsaved_changes_message) + .setPositiveButton(R.string.button_save, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + // Save + saveNote(); + finish(); + } + }) + .setNeutralButton(R.string.button_dont_save, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + // Don't save + finish(); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + // Cancel + } + }) + .create(); } @Override @@ -2043,7 +2077,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (mState == STATE_EDIT_NOTE_FROM_SDCARD) { mFileContent = mText.getText().toString(); - if (!mFileContent.equals(mOriginalContent)) { + if (! mFileContent.equals(mOriginalContent)) { // Show a dialog showDialog(DIALOG_UNSAVED_CHANGES); return true; @@ -2054,65 +2088,58 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (debug) - Log.d(TAG, "onActivityResult: Received requestCode " + requestCode - + ", resultCode " + resultCode); - switch (requestCode) { - case REQUEST_CODE_DECRYPT: - if (resultCode == RESULT_OK && data != null) { - String decryptedText = data - .getStringExtra(CryptoIntents.EXTRA_TEXT); - long id = data.getLongExtra(PrivateNotePadIntents.EXTRA_ID, -1); - - // TODO: Check that id corresponds to current intent. - - if (id == -1) { - Log.e(TAG, "Wrong extra id"); - Toast.makeText(this, "Decrypted information incomplete", - Toast.LENGTH_SHORT).show(); + protected void onActivityResult (int requestCode, int resultCode, Intent data) { + if (debug) Log.d(TAG, "onActivityResult: Received requestCode " + requestCode + ", resultCode " + resultCode); + switch(requestCode) { + case REQUEST_CODE_DECRYPT: + if (resultCode == RESULT_OK && data != null) { + String decryptedText = data.getStringExtra (CryptoIntents.EXTRA_TEXT); + long id = data.getLongExtra(PrivateNotePadIntents.EXTRA_ID, -1); - finish(); - return; - } + // TODO: Check that id corresponds to current intent. - if (debug) - Log.d(TAG, "decrypted text received: " + decryptedText); - mDecryptedText = decryptedText; - mOriginalContent = decryptedText; + if (id == -1) { + Log.e(TAG, "Wrong extra id"); + Toast.makeText(this, + "Decrypted information incomplete", + Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(this, R.string.decryption_failed, - Toast.LENGTH_SHORT).show(); - Log.e(TAG, "decryption failed"); + finish(); + return; + } - finish(); - } - break; - case REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE: - if (resultCode == RESULT_OK && data != null) { - // Insert result at current cursor position: - mApplyText = data.getStringExtra(NotepadIntents.EXTRA_TEXT); - mApplyTextBefore = data - .getStringExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION); - mApplyTextAfter = data - .getStringExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION); - - // Text is actually inserted in onResume() - see - // applyInsertText() - } - break; - case REQUEST_CODE_SAVE_AS: - if (resultCode == RESULT_OK && data != null) { - // Set the new file name - mUri = data.getData(); - if (debug) - Log.d(TAG, "original: " + mOriginalContent + ", file: " - + mFileContent); - mOriginalContent = mFileContent; - - updateTitleSdCard(); - } + if (debug) Log.d(TAG, "decrypted text received: " + decryptedText); + mDecryptedText = decryptedText; + mOriginalContent = decryptedText; + + } else { + Toast.makeText(this, + R.string.decryption_failed, + Toast.LENGTH_SHORT).show(); + Log.e(TAG, "decryption failed"); + + finish(); + } + break; + case REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE: + if (resultCode == RESULT_OK && data != null) { + // Insert result at current cursor position: + mApplyText = data.getStringExtra(NotepadIntents.EXTRA_TEXT); + mApplyTextBefore = data.getStringExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION); + mApplyTextAfter = data.getStringExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION); + + // Text is actually inserted in onResume() - see applyInsertText() + } + break; + case REQUEST_CODE_SAVE_AS: + if (resultCode == RESULT_OK && data != null) { + // Set the new file name + mUri = data.getData(); + if (debug) Log.d(TAG, "original: " + mOriginalContent + ", file: " + mFileContent); + mOriginalContent = mFileContent; + + updateTitleSdCard(); + } } } } \ No newline at end of file diff --git a/NotePad/src/org/openintents/notepad/NotePad.java b/NotePad/src/org/openintents/notepad/NotePad.java index 46942fd..0b75440 100644 --- a/NotePad/src/org/openintents/notepad/NotePad.java +++ b/NotePad/src/org/openintents/notepad/NotePad.java @@ -35,22 +35,19 @@ public final class NotePad { public static final String AUTHORITY = "org.openintents.notepad"; // This class cannot be instantiated - private NotePad() { - } + private NotePad() {} /** * Notes table */ public static final class Notes implements BaseColumns { // This class cannot be instantiated - private Notes() { - } + private Notes() {} /** * The content:// style URL for this table */ - public static final Uri CONTENT_URI = Uri.parse("content://" - + AUTHORITY + "/notes"); + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of notes. @@ -58,109 +55,90 @@ private Notes() { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.openintents.notepad.note"; /** - * The MIME type of a {@link #CONTENT_URI} sub-directory of a single - * note. + * The MIME type of a {@link #CONTENT_URI} sub-directory of a single note. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.openintents.notepad.note"; /** * The title of the note - * <P> - * Type: TEXT - * </P> + * <P>Type: TEXT</P> */ public static final String TITLE = "title"; /** * The note itself - * <P> - * Type: TEXT - * </P> + * <P>Type: TEXT</P> */ public static final String NOTE = "note"; /** * The timestamp for when the note was created - * <P> - * Type: INTEGER (long from System.curentTimeMillis()) - * </P> + * <P>Type: INTEGER (long from System.curentTimeMillis())</P> */ public static final String CREATED_DATE = "created"; /** * The timestamp for when the note was last modified - * <P> - * Type: INTEGER (long from System.curentTimeMillis()) - * </P> + * <P>Type: INTEGER (long from System.curentTimeMillis())</P> */ public static final String MODIFIED_DATE = "modified"; /** - * Tags associated with a note. Multiple tags are separated by commas. - * <P> - * Type: TEXT - * </P> - * + * Tags associated with a note. + * Multiple tags are separated by commas. + * <P>Type: TEXT</P> * @since 1.1.0 */ public static final String TAGS = "tags"; /** - * Whether the note is encrypted. 0 = not encrypted. 1 = encrypted. - * <P> - * Type: INTEGER - * </P> - * + * Whether the note is encrypted. + * 0 = not encrypted. 1 = encrypted. + * <P>Type: INTEGER</P> * @since 1.1.0 */ public static final String ENCRYPTED = "encrypted"; /** * A theme URI. - * <P> - * Type: TEXT - * </P> - * + * <P>Type: TEXT</P> * @since 1.1.0 */ public static final String THEME = "theme"; - + + /** + * A R.color.id + * <P>Type: INT</P> + * @since 1.3.0 + */ + public static final String COLOR = "color"; + /** * The starting position of the selection in the note. - * <p> - * TYPE: INTEGER - * </p> - * + * <p>TYPE: INTEGER</p> * @since 1.2.3 */ public static final String SELECTION_START = "selection_start"; - + /** * The ending position of the selection in the note. - * <p> - * TYPE: INTEGER - * </p> - * + * <p>TYPE: INTEGER</p> * @since 1.2.3 */ public static final String SELECTION_END = "selection_end"; - + /** - * The scroll position in the list expressed as scrollY/height TODO - * Implement. - * <p> - * TYPE: REAL - * </p> - * + * The scroll position in the list expressed as scrollY/height + * TODO Implement. + * <p>TYPE: REAL</p> * @since 1.2.3 */ public static final String SCROLL_POSITION = "scroll_position"; /** - * Support sort orders. The "sort order" in the preferences is an index - * into this array. + * Support sort orders. The "sort order" in the preferences + * is an index into this array. */ - public static final String[] SORT_ORDERS = { "title ASC", "title DESC", - "modified DESC", "modified ASC", "created DESC", "created ASC" }; + public static final String[] SORT_ORDERS = {"title ASC", "title DESC", "modified DESC", "modified ASC", "created DESC", "created ASC"}; } } diff --git a/NotePad/src/org/openintents/notepad/NotePadProvider.java b/NotePad/src/org/openintents/notepad/NotePadProvider.java index 662d8b4..4e8b2e8 100644 --- a/NotePad/src/org/openintents/notepad/NotePadProvider.java +++ b/NotePad/src/org/openintents/notepad/NotePadProvider.java @@ -16,6 +16,7 @@ package org.openintents.notepad; + import java.util.HashMap; import org.openintents.intents.ProviderIntents; @@ -56,7 +57,7 @@ public class NotePadProvider extends ContentProvider { * <li>Version 4 (1.2.3 - ): selection_start, selection_end</li> * </ul> */ - private static final int DATABASE_VERSION = 4; + private static final int DATABASE_VERSION = 5; private static final String NOTES_TABLE_NAME = "notes"; private static HashMap<String, String> sNotesProjectionMap; @@ -77,20 +78,24 @@ private static class DatabaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " - + NOTES_TABLE_NAME - + " (" + db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " (" // Version 2: - + Notes._ID + " INTEGER PRIMARY KEY," + Notes.TITLE - + " TEXT," + Notes.NOTE + " TEXT," + Notes.CREATED_DATE - + " INTEGER," + Notes.MODIFIED_DATE - + " INTEGER," + + Notes._ID + " INTEGER PRIMARY KEY," + + Notes.TITLE + " TEXT," + + Notes.NOTE + " TEXT," + + Notes.CREATED_DATE + " INTEGER," + + Notes.MODIFIED_DATE + " INTEGER," // Version 3: - + Notes.TAGS + " TEXT," + Notes.ENCRYPTED + " INTEGER," + + Notes.TAGS + " TEXT," + + Notes.ENCRYPTED + " INTEGER," + Notes.THEME + " TEXT," // Version 4: - + Notes.SELECTION_START + " INTEGER," + Notes.SELECTION_END - + " INTEGER," + Notes.SCROLL_POSITION + " REAL" + ");"); + + Notes.SELECTION_START + " INTEGER," + + Notes.SELECTION_END + " INTEGER," + + Notes.SCROLL_POSITION + " REAL," + // Version 5: + + Notes.COLOR + " INTEGER" + + ");"); } @Override @@ -99,59 +104,60 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + newVersion + "."); if (newVersion > oldVersion) { // Upgrade - switch (oldVersion) { - case 2: - // Upgrade from version 2 to 3. - // It seems SQLite3 only allows to add one column at a time, - // so we need three SQL statements: - try { - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME - + " ADD COLUMN " + Notes.TAGS + " TEXT;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME - + " ADD COLUMN " + Notes.ENCRYPTED - + " INTEGER;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME - + " ADD COLUMN " + Notes.THEME + " TEXT;"); - } catch (SQLException e) { - Log.e(TAG, "Error executing SQL: ", e); - // If the error is "duplicate column name" then - // everything is fine, - // as this happens after upgrading 2->3, then - // downgrading 3->2, - // and then upgrading again 2->3. - } - // fall through for further upgrades. - - case 3: - // Upgrade from version 3 to 4 - try { - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME - + " ADD COLUMN " + Notes.SELECTION_START - + " INTEGER;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME - + " ADD COLUMN " + Notes.SELECTION_END - + " INTEGER;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME - + " ADD COLUMN " + Notes.SCROLL_POSITION - + " REAL;"); - } catch (SQLException e) { - Log.e(TAG, "Error executing SQL: ", e); - } - - case 4: - // add more columns here - break; - - default: - Log.w(TAG, "Unknown version " + oldVersion - + ". Creating new database."); - db.execSQL("DROP TABLE IF EXISTS notes"); - onCreate(db); + switch(oldVersion) { + case 2: + // Upgrade from version 2 to 3. + // It seems SQLite3 only allows to add one column at a time, + // so we need three SQL statements: + try { + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.TAGS + " TEXT;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.ENCRYPTED + " INTEGER;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.THEME + " TEXT;"); + } catch (SQLException e) { + Log.e(TAG, "Error executing SQL: ", e); + // If the error is "duplicate column name" then everything is fine, + // as this happens after upgrading 2->3, then downgrading 3->2, + // and then upgrading again 2->3. + } + // fall through for further upgrades. + + case 3: + // Upgrade from version 3 to 4 + try { + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.SELECTION_START + " INTEGER;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.SELECTION_END + " INTEGER;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.SCROLL_POSITION + " REAL;"); + } catch (SQLException e) { + Log.e(TAG, "Error executing SQL: ", e); + } + + case 4: + // add more columns here + try { + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.COLOR + " INTEGER;"); + } catch (SQLException e) { + Log.e(TAG, "Error executing SQL: ", e); + } + break; + case 5: + // add more columns here + break; + + default: + Log.w(TAG, "Unknown version " + oldVersion + ". Creating new database."); + db.execSQL("DROP TABLE IF EXISTS notes"); + onCreate(db); } } else { // newVersion <= oldVersion // Downgrade - Log.w(TAG, - "Don't know how to downgrade. Will not touch database and hope they are compatible."); + Log.w(TAG, "Don't know how to downgrade. Will not touch database and hope they are compatible."); // Do nothing. } } @@ -166,24 +172,24 @@ public boolean onCreate() { } @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch (sUriMatcher.match(uri)) { - case NOTES: - qb.setTables(NOTES_TABLE_NAME); - qb.setProjectionMap(sNotesProjectionMap); - break; - - case NOTE_ID: - qb.setTables(NOTES_TABLE_NAME); - qb.setProjectionMap(sNotesProjectionMap); - qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1)); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); + case NOTES: + qb.setTables(NOTES_TABLE_NAME); + qb.setProjectionMap(sNotesProjectionMap); + break; + + case NOTE_ID: + qb.setTables(NOTES_TABLE_NAME); + qb.setProjectionMap(sNotesProjectionMap); + qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1)); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); } // If no sort order is specified use the default @@ -196,11 +202,9 @@ public Cursor query(Uri uri, String[] projection, String selection, // Get the database and run the query SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - Cursor c = qb.query(db, projection, selection, selectionArgs, null, - null, orderBy); + Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); - // Tell the cursor what uri to watch, so it knows when its source data - // changes + // Tell the cursor what uri to watch, so it knows when its source data changes c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @@ -208,14 +212,14 @@ public Cursor query(Uri uri, String[] projection, String selection, @Override public String getType(Uri uri) { switch (sUriMatcher.match(uri)) { - case NOTES: - return Notes.CONTENT_TYPE; + case NOTES: + return Notes.CONTENT_TYPE; - case NOTE_ID: - return Notes.CONTENT_ITEM_TYPE; + case NOTE_ID: + return Notes.CONTENT_ITEM_TYPE; - default: - throw new IllegalArgumentException("Unknown URI " + uri); + default: + throw new IllegalArgumentException("Unknown URI " + uri); } } @@ -246,31 +250,33 @@ public Uri insert(Uri uri, ContentValues initialValues) { if (values.containsKey(NotePad.Notes.TITLE) == false) { Resources r = Resources.getSystem(); - values.put(NotePad.Notes.TITLE, - r.getString(android.R.string.untitled)); + values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled)); } if (values.containsKey(NotePad.Notes.NOTE) == false) { values.put(NotePad.Notes.NOTE, ""); } - - if (values.containsKey(Notes.SELECTION_START) == false) { + + if(values.containsKey(Notes.SELECTION_START) == false) { values.put(Notes.SELECTION_START, 0); } - - if (values.containsKey(Notes.SELECTION_END) == false) { + + if(values.containsKey(Notes.SELECTION_END) == false) { values.put(Notes.SELECTION_END, 0); } - - if (values.containsKey(Notes.SCROLL_POSITION) == false) { + + if(values.containsKey(Notes.SCROLL_POSITION) == false) { values.put(Notes.SCROLL_POSITION, 0.0); } + if(values.containsKey(Notes.COLOR) == false) { + values.put(Notes.COLOR, -1); + } + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values); if (rowId > 0) { - Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, - rowId); + Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(noteUri, null); Intent intent = new Intent(ProviderIntents.ACTION_INSERTED); @@ -289,24 +295,22 @@ public int delete(Uri uri, String where, String[] whereArgs) { int count; long[] affectedRows = null; switch (sUriMatcher.match(uri)) { - case NOTES: - affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, - where, whereArgs); - count = db.delete(NOTES_TABLE_NAME, where, whereArgs); - break; - - case NOTE_ID: - String noteId = uri.getPathSegments().get(1); - String whereString = Notes._ID + "=" + noteId - + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""); - - affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, - whereString, whereArgs); - count = db.delete(NOTES_TABLE_NAME, whereString, whereArgs); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); + case NOTES: + affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, where, whereArgs); + count = db.delete(NOTES_TABLE_NAME, where, whereArgs); + break; + + case NOTE_ID: + String noteId = uri.getPathSegments().get(1); + String whereString = Notes._ID + "=" + noteId + + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""); + + affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, whereString, whereArgs); + count = db.delete(NOTES_TABLE_NAME, whereString, whereArgs); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); @@ -320,27 +324,22 @@ public int delete(Uri uri, String where, String[] whereArgs) { } @Override - public int update(Uri uri, ContentValues values, String where, - String[] whereArgs) { + public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; switch (sUriMatcher.match(uri)) { - case NOTES: - count = db.update(NOTES_TABLE_NAME, values, where, whereArgs); - break; - - case NOTE_ID: - String noteId = uri.getPathSegments().get(1); - count = db.update(NOTES_TABLE_NAME, values, - Notes._ID - + "=" - + noteId - + (!TextUtils.isEmpty(where) ? " AND (" + where - + ')' : ""), whereArgs); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); + case NOTES: + count = db.update(NOTES_TABLE_NAME, values, where, whereArgs); + break; + + case NOTE_ID: + String noteId = uri.getPathSegments().get(1); + count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); @@ -369,5 +368,6 @@ public int update(Uri uri, ContentValues values, String where, sNotesProjectionMap.put(Notes.SELECTION_START, Notes.SELECTION_START); sNotesProjectionMap.put(Notes.SELECTION_END, Notes.SELECTION_END); sNotesProjectionMap.put(Notes.SCROLL_POSITION, Notes.SCROLL_POSITION); + sNotesProjectionMap.put(Notes.COLOR, Notes.COLOR); } } diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesList.java b/NotePad/src/org/openintents/notepad/noteslist/NotesList.java index 32da65d..c301f7d 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesList.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesList.java @@ -32,7 +32,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Locale; +import java.util.Locale; + import org.openintents.distribution.DistributionLibraryListActivity; import org.openintents.distribution.DownloadOIAppDialog; @@ -91,8 +92,7 @@ * the intent if there is one, otherwise defaults to displaying the contents of * the {@link NotePadProvider} */ -public class NotesList extends DistributionLibraryListActivity implements - ListView.OnScrollListener, OnDismissListener { +public class NotesList extends DistributionLibraryListActivity implements ListView.OnScrollListener, OnDismissListener { private static final String TAG = "NotesList"; private static final boolean debug = false; @@ -103,13 +103,11 @@ public class NotesList extends DistributionLibraryListActivity implements private static final int MENU_ITEM_ENCRYPT = Menu.FIRST + 5; private static final int MENU_ITEM_UNENCRYPT = Menu.FIRST + 6; private static final int MENU_ITEM_EDIT_TAGS = Menu.FIRST + 7; - // private static final int MENU_ITEM_SAVE = Menu.FIRST + 8; + //private static final int MENU_ITEM_SAVE = Menu.FIRST + 8; private static final int MENU_OPEN = Menu.FIRST + 9; private static final int MENU_SETTINGS = Menu.FIRST + 10; private static final int MENU_SEARCH = Menu.FIRST + 11; - private static final int MENU_DISTRIBUTION_START = Menu.FIRST + 100; // MUST - // BE - // LAST + private static final int MENU_DISTRIBUTION_START = Menu.FIRST + 100; // MUST BE LAST private static final String BUNDLE_LAST_FILTER = "last_filter"; @@ -122,7 +120,7 @@ public class NotesList extends DistributionLibraryListActivity implements private final static int CATEGORY_ALTERNATIVE_GLOBAL = 1; private static final int REQUEST_CODE_DECRYPT_TITLE = 3; - // private static final int REQUEST_CODE_UNENCRYPT_NOTE = 4; + //private static final int REQUEST_CODE_UNENCRYPT_NOTE = 4; private static final int REQUEST_CODE_OPEN = 5; private static final int DIALOG_TAGS = 1; @@ -142,32 +140,30 @@ public class NotesList extends DistributionLibraryListActivity implements private boolean mDecryptionFailed; private boolean mDecryptionSucceeded; - + private static boolean mActionBarAvailable; - + static { try { WrapActionBar.checkAvailable(); mActionBarAvailable = true; - } catch (Throwable t) { + } catch(Throwable t){ mActionBarAvailable = false; } } AdapterView.AdapterContextMenuInfo mContextMenuInfo; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (debug) { - Log.d(TAG, "onCreate() " - + (savedInstanceState == null ? "(no bundle)" - : "(with bundle)")); + Log.d(TAG, "onCreate() " + (savedInstanceState == null ? "(no bundle)" : "(with bundle)")); } - mDistribution.setFirst(MENU_DISTRIBUTION_START, - DIALOG_DISTRIBUTION_START); + mDistribution.setFirst(MENU_DISTRIBUTION_START, DIALOG_DISTRIBUTION_START); // Check whether EULA has been accepted // or information about new version can be presented. @@ -183,8 +179,8 @@ protected void onCreate(Bundle savedInstanceState) { if (intent.getData() == null) { intent.setData(Notes.CONTENT_URI); } - - // show loading + + //show loading requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); requestWindowFeature(Window.FEATURE_PROGRESS); @@ -204,17 +200,20 @@ protected void onCreate(Bundle savedInstanceState) { */ /* - * // Perform a managed query. The Activity will handle closing and // - * requerying the cursor // when needed. Cursor cursor = - * managedQuery(getIntent().getData(), PROJECTION, null, null, - * Notes.DEFAULT_SORT_ORDER); - * - * /* // Used to map notes entries from the database to views - * SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, - * R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, new - * int[] { android.R.id.text1 }); / mAdapter = new - * NotesListCursorAdapter(this, cursor, getIntent()); - * setListAdapter(mAdapter); + // Perform a managed query. The Activity will handle closing and + // requerying the cursor + // when needed. + Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, + null, Notes.DEFAULT_SORT_ORDER); + + /* + // Used to map notes entries from the database to views + SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, + new int[] { android.R.id.text1 }); + * / + mAdapter = new NotesListCursorAdapter(this, cursor, getIntent()); + setListAdapter(mAdapter); */ getListView().setOnScrollListener(this); @@ -227,10 +226,8 @@ protected void onCreate(Bundle savedInstanceState) { // Restore information for context menu, for opening "Tags" dialog. if (savedInstanceState.containsKey(BUNDLE_CONTEXTMENUINFO_ID)) { long id = savedInstanceState.getLong(BUNDLE_CONTEXTMENUINFO_ID); - int position = savedInstanceState - .getInt(BUNDLE_CONTEXTMENUINFO_POSITION); - mContextMenuInfo = new AdapterView.AdapterContextMenuInfo(null, - position, id); + int position = savedInstanceState.getInt(BUNDLE_CONTEXTMENUINFO_POSITION); + mContextMenuInfo = new AdapterView.AdapterContextMenuInfo(null, position, id); } } @@ -257,23 +254,23 @@ public void onChanged() { }); Spinner s = (Spinner) findViewById(R.id.tagselection); - s.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + s.setOnItemSelectedListener( + new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView<?> arg0, View arg1, - int arg2, long arg3) { - NotesList.this.updateQuery(); - decryptDelayed(); - } + public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { + NotesList.this.updateQuery(); + decryptDelayed(); + } - public void onNothingSelected(AdapterView<?> arg0) { + public void onNothingSelected(AdapterView<?> arg0) { - } - }); + } + }); mDecryptionFailed = false; mDecryptionSucceeded = false; - // disable the progressbar when done. + //disable the progressbar when done. setProgressBarIndeterminateVisibility(false); setProgressBarVisibility(false); } @@ -285,7 +282,10 @@ protected void updateTagList() { Uri notesUri = getIntent().getData(); Cursor managedCursor = getContentResolver().query(notesUri, - new String[] { Notes.TAGS, Notes.ENCRYPTED }, null, null, null); + new String[]{Notes.TAGS, Notes.ENCRYPTED}, + null, + null, + null); if (managedCursor.moveToFirst()) { do { @@ -311,8 +311,7 @@ protected void updateTagList() { Collections.sort(taglist, Collator.getInstance(Locale.getDefault())); taglist.add(0, getString(R.string.all_notes)); Spinner s = (Spinner) findViewById(R.id.tagselection); - ArrayAdapter adapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_item, taglist); + ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, taglist); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); s.setAdapter(adapter); @@ -327,15 +326,15 @@ protected void updateTagList() { @Override protected void onResume() { super.onResume(); - if (debug) - Log.d(TAG, "onResume()"); + if (debug) Log.d(TAG, "onResume()"); NotesListCursor.mSuspendQueries = false; - // mCursorUtils.registerContentObserver(mListContentObserver); - // mCursorUtils.registerDataSetObserver(mListDatasetObserver); + //mCursorUtils.registerContentObserver(mListContentObserver); + //mCursorUtils.registerDataSetObserver(mListDatasetObserver); checkAdapter(); + if (!mDecryptionFailed) { decryptDelayed(); } else { @@ -345,56 +344,66 @@ protected void onResume() { if (mDecryptionSucceeded) { NotesListCursor.mLoggedIn = true; - if (debug) - Log.d(TAG, "onResume: logged in"); + if (debug) Log.d(TAG, "onResume: logged in"); } IntentFilter filter = new IntentFilter(); filter.addAction(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); registerReceiver(mBroadcastReceiver, filter); + // getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); } - /* - * ContentObserver mListContentObserver = new ContentObserver(mHandler) { - * - * @Override public boolean deliverSelfNotifications() { Log.i(TAG, - * "NotesList:mListContentObserver: deliverSelfNotifications"); return - * super.deliverSelfNotifications(); } - * - * @Override public void onChange(boolean arg0) { Log.i(TAG, - * "NotesList:mListContentObserver: onChange"); - * //mCursorListFilter.requery(); updateTagList(); - * - * super.onChange(arg0); } }; - * - * DataSetObserver mListDatasetObserver = new DataSetObserver() { - * - * @Override public void onChanged() { Log.i(TAG, - * "mListDatasetObserver: onChanged"); super.onChanged(); } - * - * @Override public void onInvalidated() { Log.i(TAG, - * "mListDatasetObserver: onInvalidated"); super.onInvalidated(); } - * - * }; + ContentObserver mListContentObserver = new ContentObserver(mHandler) { + + @Override + public boolean deliverSelfNotifications() { + Log.i(TAG, "NotesList:mListContentObserver: deliverSelfNotifications"); + return super.deliverSelfNotifications(); + } + + @Override + public void onChange(boolean arg0) { + Log.i(TAG, "NotesList:mListContentObserver: onChange"); + //mCursorListFilter.requery(); + updateTagList(); + + super.onChange(arg0); + } + }; + + DataSetObserver mListDatasetObserver = new DataSetObserver() { + + @Override + public void onChanged() { + Log.i(TAG, "mListDatasetObserver: onChanged"); + super.onChanged(); + } + + @Override + public void onInvalidated() { + Log.i(TAG, "mListDatasetObserver: onInvalidated"); + super.onInvalidated(); + } + + }; */ private void checkAdapter() { if (mAdapter == null) { // Perform a managed query. The Activity will handle closing and // requerying the cursor // when needed. - // Cursor cursor = getContentResolver().query(getIntent().getData(), - // NotesListCursorUtils.PROJECTION, null, - // null, Notes.DEFAULT_SORT_ORDER); + //Cursor cursor = getContentResolver().query(getIntent().getData(), NotesListCursorUtils.PROJECTION, null, + // null, Notes.DEFAULT_SORT_ORDER); Cursor cursor = mCursorUtils.query(null, null); /* - * // Used to map notes entries from the database to views - * SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, - * R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, - * new int[] { android.R.id.text1 }); + // Used to map notes entries from the database to views + SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, + new int[] { android.R.id.text1 }); */ mAdapter = new NotesListCursorAdapter(this, cursor, mCursorUtils); setListAdapter(mAdapter); @@ -412,18 +421,17 @@ protected void updateQuery() { Spinner s = (Spinner) findViewById(R.id.tagselection); - if (s.getSelectedItemPosition() == 0) { + if ( s.getSelectedItemPosition() == 0 ) { mSelectedTag = null; } else { mSelectedTag = (String) s.getSelectedItem(); } - // if (mLastFilter != null || mSelectedTag != null) { - Cursor cursor = mAdapter.runQueryOnBackgroundThread(mLastFilter, - mSelectedTag); + //if (mLastFilter != null || mSelectedTag != null) { + Cursor cursor = mAdapter.runQueryOnBackgroundThread(mLastFilter, mSelectedTag); mAdapter.changeCursor(cursor); - // } - } + //} +} @Override protected void onPause() { @@ -431,32 +439,32 @@ protected void onPause() { mLastFilter = mCursorUtils.mCurrentFilter; + // Deactivating the cursor leads to flickering whenever some // encrypted information is retrieved. // Cursor c = mAdapter.getCursor(); - // if (c != null) { - // c.deactivate(); - // } + //if (c != null) { + // c.deactivate(); + //} - // mCursorUtils.unregisterDataSetObserver(mListDatasetObserver); - // mCursorUtils.unregisterContentObserver(mListContentObserver); + //mCursorUtils.unregisterDataSetObserver(mListDatasetObserver); + //mCursorUtils.unregisterContentObserver(mListContentObserver); unregisterReceiver(mBroadcastReceiver); - // After unregistering broadcastreceiver, the logged in state is not - // clear. + // After unregistering broadcastreceiver, the logged in state is not clear. NotesListCursor.mLoggedIn = false; - if (debug) - Log.d(TAG, "onPause: logged out"); + if (debug) Log.d(TAG, "onPause: logged out"); - // No need wasting a lot of time doing queries when external - // applications change the + // No need wasting a lot of time doing queries when external applications change the // database - we requery in onResume anyway. NotesListCursor.mSuspendQueries = true; mDecryptionFailed = false; mDecryptionSucceeded = false; } + + @Override protected void onDestroy() { // TODO Auto-generated method stub @@ -464,6 +472,7 @@ protected void onDestroy() { } + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -472,17 +481,16 @@ protected void onSaveInstanceState(Bundle outState) { if (mContextMenuInfo != null) { outState.putLong(BUNDLE_CONTEXTMENUINFO_ID, mContextMenuInfo.id); - outState.putInt(BUNDLE_CONTEXTMENUINFO_POSITION, - mContextMenuInfo.position); + outState.putInt(BUNDLE_CONTEXTMENUINFO_POSITION, mContextMenuInfo.position); } } + @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - - MenuItem insertItem = menu.add(0, MENU_ITEM_INSERT, 0, - R.string.menu_insert); + + MenuItem insertItem = menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert); insertItem.setShortcut('1', 'i'); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Icon for holo theme @@ -490,22 +498,21 @@ public boolean onCreateOptionsMenu(Menu menu) { } else { insertItem.setIcon(android.R.drawable.ic_menu_add); } - // Show the delete icon when there is an actionbar - if (mActionBarAvailable) { + //Show the delete icon when there is an actionbar + if(mActionBarAvailable){ WrapActionBar.showIfRoom(insertItem); - TextView notext = (TextView) findViewById(R.id.empty); + TextView notext=(TextView)findViewById(R.id.empty); notext.setText(R.string.no_notes_actionbar); } - menu.add(0, MENU_SEARCH, 0, R.string.menu_search).setShortcut('2', 's') - .setIcon(android.R.drawable.ic_menu_search); + menu.add(0, MENU_SEARCH, 0, R.string.menu_search).setShortcut('2', + 's').setIcon(android.R.drawable.ic_menu_search); - menu.add(0, MENU_OPEN, 0, R.string.menu_open_from_sdcard) - .setShortcut('3', 'o').setIcon(R.drawable.ic_menu_folder); + menu.add(0, MENU_OPEN, 0, R.string.menu_open_from_sdcard).setShortcut('3', + 'o').setIcon(R.drawable.ic_menu_folder); - menu.add(0, MENU_SETTINGS, 0, R.string.settings) - .setIcon(android.R.drawable.ic_menu_preferences) - .setShortcut('9', 's'); + menu.add(0, MENU_SETTINGS, 0, R.string.settings).setIcon( + android.R.drawable.ic_menu_preferences).setShortcut('9', 's'); // Add distribution menu items last. mDistribution.onCreateOptionsMenu(menu); @@ -515,17 +522,15 @@ public boolean onCreateOptionsMenu(Menu menu) { // actions found here, but this allows other applications to extend // our menu with their own actions. Intent intent = new Intent(null, getIntent().getData()); - if (debug) - Log.i(TAG, "Building options menu for: " + intent.getDataString()); + if (debug) Log.i(TAG, "Building options menu for: " + intent.getDataString()); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); - // menu - // .addIntentOptions(CATEGORY_ALTERNATIVE_GLOBAL, 0, 0, - // new ComponentName(this, NotesList.class), null, intent, - // 0, null); + //menu + // .addIntentOptions(CATEGORY_ALTERNATIVE_GLOBAL, 0, 0, + // new ComponentName(this, NotesList.class), null, intent, + // 0, null); // Workaround to add icons: - MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, - menu); + MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, menu); menu2.addIntentOptions(CATEGORY_ALTERNATIVE_GLOBAL, 0, 0, new ComponentName(this, NotesList.class), null, intent, 0, null); @@ -555,14 +560,13 @@ public boolean onPrepareOptionsMenu(Menu menu) { // ... is followed by whatever other actions are available... Intent intent = new Intent(null, uri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); - // menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, - // specifics, intent, 0, items); + //menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, + // specifics, intent, 0, items); // Workaround to add icons: - MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons( - this, menu); - menu2.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, - specifics, intent, 0, items); + MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, menu); + menu2.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, + null, specifics, intent, 0, items); // Give a shortcut to the edit action. if (items[0] != null) { @@ -578,18 +582,18 @@ public boolean onPrepareOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case MENU_ITEM_INSERT: - insertNewNote(); - return true; - case MENU_SEARCH: - search(); - return true; - case MENU_OPEN: - openFromSdCard(); - return true; - case MENU_SETTINGS: - showNotesListSettings(); - return true; + case MENU_ITEM_INSERT: + insertNewNote(); + return true; + case MENU_SEARCH: + search(); + return true; + case MENU_OPEN: + openFromSdCard(); + return true; + case MENU_SETTINGS: + showNotesListSettings(); + return true; } return super.onOptionsItemSelected(item); } @@ -618,8 +622,7 @@ private void openFromSdCard() { Uri uri = FileUriUtils.getUri(directory); Intent i = new Intent(this, DialogHostingActivity.class); - i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, - DialogHostingActivity.DIALOG_ID_OPEN); + i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_OPEN); i.setData(uri); startActivityForResult(i, REQUEST_CODE_OPEN); } @@ -641,14 +644,13 @@ public void onCreateContextMenu(ContextMenu menu, View view, return; } - Uri noteUri = ContentUris - .withAppendedId(getIntent().getData(), info.id); + Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), + info.id); long encrypted = cursor.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); // Setup the menu header - menu.setHeaderTitle(cursor - .getString(NotesListCursor.COLUMN_INDEX_TITLE)); + menu.setHeaderTitle(cursor.getString(NotesListCursor.COLUMN_INDEX_TITLE)); menu.add(0, MENU_ITEM_EDIT_TAGS, 0, R.string.menu_edit_tags); @@ -658,7 +660,7 @@ public void onCreateContextMenu(ContextMenu menu, View view, menu.add(0, MENU_ITEM_SHARE, 0, R.string.menu_share); // Added automatically through manifest: - // menu.add(0, MENU_ITEM_SAVE, 0, R.string.menu_save_to_sdcard); + //menu.add(0, MENU_ITEM_SAVE, 0, R.string.menu_save_to_sdcard); menu.add(0, MENU_ITEM_ENCRYPT, 0, R.string.menu_encrypt); } else { @@ -674,8 +676,7 @@ public void onCreateContextMenu(ContextMenu menu, View view, Intent intent = new Intent(null, noteUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, - new ComponentName(this, NotesList.class), null, intent, 0, - null); + new ComponentName(this, NotesList.class), null, intent, 0, null); } } @@ -683,35 +684,34 @@ public void onCreateContextMenu(ContextMenu menu, View view, @Override public boolean onContextItemSelected(MenuItem item) { try { - mContextMenuInfo = (AdapterView.AdapterContextMenuInfo) item - .getMenuInfo(); + mContextMenuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); } catch (ClassCastException e) { Log.e(TAG, "bad menuInfo", e); return false; } switch (item.getItemId()) { - case MENU_ITEM_DELETE: { - showDialog(DIALOG_DELETE); - // mAdapter.getCursor().requery(); - return true; - } - case MENU_ITEM_SHARE: - sendNoteByEmail(mContextMenuInfo.id); - return true; - case MENU_ITEM_ENCRYPT: - encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_ENCRYPT); - return true; - case MENU_ITEM_UNENCRYPT: - encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_DECRYPT); - return true; - case MENU_ITEM_EDIT_TAGS: - editTags(); - - return true; - // case MENU_ITEM_SAVE: - // saveToSdCard(); - // return true; + case MENU_ITEM_DELETE: { + showDialog(DIALOG_DELETE); + //mAdapter.getCursor().requery(); + return true; + } + case MENU_ITEM_SHARE: + sendNoteByEmail(mContextMenuInfo.id); + return true; + case MENU_ITEM_ENCRYPT: + encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_ENCRYPT); + return true; + case MENU_ITEM_UNENCRYPT: + encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_DECRYPT); + return true; + case MENU_ITEM_EDIT_TAGS: + editTags(); + + return true; + //case MENU_ITEM_SAVE: + // saveToSdCard(); + // return true; } return false; } @@ -733,10 +733,8 @@ private void sendNoteByEmail(long id) { content = c.getString(1); } - if (debug) - Log.i(TAG, "Title to send: " + title); - if (debug) - Log.i(TAG, "Content to send: " + content); + if (debug) Log.i(TAG, "Title to send: " + title); + if (debug) Log.i(TAG, "Content to send: " + content); SendNote.sendNote(this, title, content); } @@ -751,10 +749,8 @@ private void encryptNote(long id, String action) { Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), id); // getContentResolver().(noteUri, null, null); - Cursor c = getContentResolver().query( - noteUri, - new String[] { NotePad.Notes.TITLE, NotePad.Notes.NOTE, - NotePad.Notes.TAGS, NotePad.Notes.ENCRYPTED }, null, + Cursor c = getContentResolver().query(noteUri, + new String[] { NotePad.Notes.TITLE, NotePad.Notes.NOTE, NotePad.Notes.TAGS, NotePad.Notes.ENCRYPTED }, null, null, PreferenceActivity.getSortOrderFromPrefs(this)); String title = ""; @@ -770,21 +766,22 @@ private void encryptNote(long id, String action) { } if (action.equals(CryptoIntents.ACTION_ENCRYPT) && encrypted != 0) { - Toast.makeText(this, R.string.already_encrypted, Toast.LENGTH_SHORT) - .show(); + Toast.makeText(this, + R.string.already_encrypted, + Toast.LENGTH_SHORT).show(); return; } if (action.equals(CryptoIntents.ACTION_DECRYPT) && encrypted == 0) { - Toast.makeText(this, R.string.not_encrypted, Toast.LENGTH_SHORT) - .show(); + Toast.makeText(this, + R.string.not_encrypted, + Toast.LENGTH_SHORT).show(); return; } Intent i = new Intent(this, EncryptActivity.class); i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, action); - i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, - EncryptActivity.getCryptoStringArray(text, title, tags)); + i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, EncryptActivity.getCryptoStringArray(text, title, tags)); i.putExtra(PrivateNotePadIntents.EXTRA_URI, noteUri.toString()); startActivity(i); } @@ -793,48 +790,57 @@ private void editTags() { showDialog(DIALOG_TAGS); } + private File getSdCardPath() { - return android.os.Environment.getExternalStorageDirectory(); + return android.os.Environment + .getExternalStorageDirectory(); } private void showNotesListSettings() { startActivity(new Intent(this, PreferenceActivity.class)); } - public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { + + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, + int totalItemCount) { } + public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { - case OnScrollListener.SCROLL_STATE_IDLE: - Log.i(TAG, "idle"); - mAdapter.mBusy = false; - - if (!NotesListCursor.mEncryptedStringList.isEmpty()) { - String encryptedString = NotesListCursor.mEncryptedStringList - .remove(0); - Log.i(TAG, "Decrypt idle: " + encryptedString); - decryptTitle(encryptedString); - } - /* - * int first = view.getFirstVisiblePosition(); int count = - * view.getChildCount(); for (int i=0; i<count; i++) { - * NotesListItemView t = (NotesListItemView)view.getChildAt(i); - * String encryptedTitle = (String) t.getTag(); if (encryptedTitle - * != null) { // Retrieve decrypted title - * decryptTitle(encryptedTitle); t.setTag(null); - * - * // decrypt one item at a time. break; } } - */ - - break; - case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: - mAdapter.mBusy = true; - break; - case OnScrollListener.SCROLL_STATE_FLING: - mAdapter.mBusy = true; - break; + case OnScrollListener.SCROLL_STATE_IDLE: + Log.i(TAG, "idle"); + mAdapter.mBusy = false; + + if (!NotesListCursor.mEncryptedStringList.isEmpty()) { + String encryptedString = NotesListCursor.mEncryptedStringList.remove(0); + Log.i(TAG, "Decrypt idle: " + encryptedString); + decryptTitle(encryptedString); + } + /* + int first = view.getFirstVisiblePosition(); + int count = view.getChildCount(); + for (int i=0; i<count; i++) { + NotesListItemView t = (NotesListItemView)view.getChildAt(i); + String encryptedTitle = (String) t.getTag(); + if (encryptedTitle != null) { + // Retrieve decrypted title + decryptTitle(encryptedTitle); + t.setTag(null); + + // decrypt one item at a time. + break; + } + } + */ + + break; + case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: + mAdapter.mBusy = true; + break; + case OnScrollListener.SCROLL_STATE_FLING: + mAdapter.mBusy = true; + break; } } @@ -876,8 +882,7 @@ public void decryptTitle(String encryptedTitle) { intent.setAction(CryptoIntents.ACTION_DECRYPT); if (encryptedTitle != null) { intent.putExtra(CryptoIntents.EXTRA_TEXT, encryptedTitle); - intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, - encryptedTitle); + intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, encryptedTitle); } intent.putExtra(CryptoIntents.EXTRA_PROMPT, false); @@ -887,72 +892,75 @@ public void decryptTitle(String encryptedTitle) { } catch (ActivityNotFoundException e) { mDecryptionFailed = true; /* - * Toast.makeText(this, R.string.decryption_failed, - * Toast.LENGTH_SHORT).show(); + Toast.makeText(this, + R.string.decryption_failed, + Toast.LENGTH_SHORT).show(); */ Log.e(TAG, "failed to invoke encrypt"); } } + @Override protected Dialog onCreateDialog(int id) { switch (id) { - case DIALOG_TAGS: - TagsDialog td = new TagsDialog(this); - td.setOnDismissListener(this); - return td; - // return new TagsDialog(this); - case DIALOG_GET_FROM_MARKET: - return new DownloadOIAppDialog(this, DownloadOIAppDialog.OI_SAFE); - case DIALOG_DELETE: - return new DeleteConfirmationDialog(this, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - Uri noteUri = ContentUris.withAppendedId( - getIntent().getData(), mContextMenuInfo.id); - getContentResolver().delete(noteUri, null, null); - updateTagList(); - } - }).create(); + case DIALOG_TAGS: + TagsDialog td = new TagsDialog(this); + td.setOnDismissListener(this); + return td; + //return new TagsDialog(this); + case DIALOG_GET_FROM_MARKET: + return new DownloadOIAppDialog(this, + DownloadOIAppDialog.OI_SAFE); + case DIALOG_DELETE: + return new DeleteConfirmationDialog(this, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), + mContextMenuInfo.id); + getContentResolver().delete(noteUri, null, null); + updateTagList(); + } + }).create(); } return super.onCreateDialog(id); } + @Override protected void onPrepareDialog(int id, Dialog dialog) { - if (debug) - Log.d(TAG, "onPrepareDialog()"); + if (debug) Log.d(TAG, "onPrepareDialog()"); switch (id) { - case DIALOG_TAGS: - TagsDialog d = (TagsDialog) dialog; - Uri uri = ContentUris.withAppendedId(getIntent().getData(), - mContextMenuInfo.id); - - Cursor c = mAdapter.getCursor(); - c.moveToPosition(mContextMenuInfo.position); - String tags = c.getString(NotesListCursor.COLUMN_INDEX_TAGS); - long encrypted = c.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); - - d.setUri(uri); - d.setTags(tags); - d.setEncrypted(encrypted); - - String[] taglist = getTaglist(c); - d.setTagList(taglist); - - break; - case DIALOG_GET_FROM_MARKET: - DownloadOIAppDialog.onPrepareDialog(this, dialog); - break; + case DIALOG_TAGS: + TagsDialog d = (TagsDialog) dialog; + Uri uri = ContentUris.withAppendedId(getIntent().getData(), mContextMenuInfo.id); + + Cursor c = mAdapter.getCursor(); + c.moveToPosition(mContextMenuInfo.position); + String tags = c.getString(NotesListCursor.COLUMN_INDEX_TAGS); + long encrypted = c.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); + + d.setUri(uri); + d.setTags(tags); + d.setEncrypted(encrypted); + + String[] taglist = getTaglist(c); + d.setTagList(taglist); + + break; + case DIALOG_GET_FROM_MARKET: + DownloadOIAppDialog.onPrepareDialog(this, dialog); + break; } } - - public void onDismiss(DialogInterface dialog) { - if (dialog instanceof TagsDialog) { + + public void onDismiss(DialogInterface dialog) + { + if(dialog instanceof TagsDialog) + { updateTagList(); } } @@ -960,8 +968,7 @@ public void onDismiss(DialogInterface dialog) { /** * Create list of tags. * - * Tags for notes can be comma-separated. Here we create a list of the - * unique tags. + * Tags for notes can be comma-separated. Here we create a list of the unique tags. * * @param c * @return @@ -987,7 +994,7 @@ String[] getTaglist(Cursor c) { // 1. Convert HashSet to String list. ArrayList<String> list = new ArrayList<String>(); list.addAll(tagset); - // 2. Sort the String list + // 2. Sort the String list Collections.sort(list); // 3. Convert it to String array return list.toArray(new String[0]); @@ -1002,24 +1009,22 @@ protected void onListItemClick(ListView l, View v, int position, long id) { long encrypted = c.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); - String encryptedTitle = c - .getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); + String encryptedTitle = c.getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); // are we in decrypted mode? - // Log.i(TAG, "Encrypted title: " + encryptedTitle); + //Log.i(TAG, "Encrypted title: " + encryptedTitle); String title = c.getString(NotesListCursor.COLUMN_INDEX_TITLE); - // Log.i(TAG, "title: " + title); + //Log.i(TAG, "title: " + title); if (encrypted != 0) { if (!TextUtils.isEmpty(encryptedTitle)) { // Try to decrypt first - // Log.i(TAG, "Decrypt first"); + //Log.i(TAG, "Decrypt first"); Intent intent = new Intent(); intent.setAction(CryptoIntents.ACTION_DECRYPT); intent.putExtra(CryptoIntents.EXTRA_TEXT, encryptedTitle); - intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, - encryptedTitle); + intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, encryptedTitle); intent.putExtra(CryptoIntents.EXTRA_PROMPT, true); @@ -1028,10 +1033,9 @@ protected void onListItemClick(ListView l, View v, int position, long id) { } catch (ActivityNotFoundException e) { mDecryptionFailed = true; - /* - * Toast.makeText(this, R.string.decryption_failed, - * Toast.LENGTH_SHORT).show(); - */ + /*Toast.makeText(this, + R.string.decryption_failed, + Toast.LENGTH_SHORT).show();*/ showDialog(DIALOG_GET_FROM_MARKET); Log.e(TAG, "failed to invoke encrypt"); } @@ -1047,7 +1051,7 @@ protected void onListItemClick(ListView l, View v, int position, long id) { // The caller is waiting for us to return a note selected by // the user. The have clicked on one, so return it now. setResult(RESULT_OK, new Intent().setData(uri)); - finish(); + finish (); } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) { Intent data = new Intent(Intent.ACTION_VIEW); data.setData(uri); @@ -1063,10 +1067,10 @@ protected void onListItemClick(ListView l, View v, int position, long id) { Intent shortcut = new Intent(Intent.ACTION_CREATE_SHORTCUT); shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, data); - Intent.ShortcutIconResource sir = Intent.ShortcutIconResource - .fromContext(this, R.drawable.ic_launcher_notepad); + Intent.ShortcutIconResource sir = Intent.ShortcutIconResource.fromContext(this, R.drawable.ic_launcher_notepad); shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, sir); + setResult(RESULT_OK, shortcut); finish(); } else { @@ -1075,99 +1079,101 @@ protected void onListItemClick(ListView l, View v, int position, long id) { } } - protected void onActivityResult(int requestCode, int resultCode, - Intent intent) { - if (debug) - Log.i(TAG, "Received requestCode " + requestCode + ", resultCode " - + resultCode); - switch (requestCode) { - case REQUEST_CODE_DECRYPT_TITLE: - if (resultCode == RESULT_OK && intent != null) { - String decryptedText = intent - .getStringExtra(CryptoIntents.EXTRA_TEXT); - String encryptedText = intent - .getStringExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT); - - if (encryptedText != null) { - // Log.i(TAG, "Encrypted text is not passed properly."); - // return; - - // Add decrypted text to hash: - NotesListCursor.mEncryptedStringHashMap.put(encryptedText, - decryptedText); - - if (debug) - Log.i(TAG, "Decrypted: " + encryptedText + " -> " - + decryptedText); - } - mDecryptionSucceeded = true; - NotesListCursor.mLoggedIn = true; - if (debug) - Log.d(TAG, "onActivity: logged in"); - // decrypt the next string. + protected void onActivityResult (int requestCode, int resultCode, Intent intent) { + if (debug) Log.i(TAG, "Received requestCode " + requestCode + ", resultCode " + resultCode); + switch(requestCode) { + case REQUEST_CODE_DECRYPT_TITLE: + if (resultCode == RESULT_OK && intent != null) { + String decryptedText = intent.getStringExtra (CryptoIntents.EXTRA_TEXT); + String encryptedText = intent.getStringExtra (PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT); + + if (encryptedText != null) { + //Log.i(TAG, "Encrypted text is not passed properly."); + //return; + + + // Add decrypted text to hash: + NotesListCursor.mEncryptedStringHashMap.put(encryptedText, decryptedText); + + if (debug) Log.i(TAG, "Decrypted: " + encryptedText + " -> " + decryptedText); + } + mDecryptionSucceeded = true; + NotesListCursor.mLoggedIn = true; + if (debug) Log.d(TAG, "onActivity: logged in"); + + // decrypt the next string. + + decryptDelayed(); - decryptDelayed(); - } else { - mDecryptionFailed = true; - setProgressBarIndeterminateVisibility(false); - } - break; - case REQUEST_CODE_OPEN: - if (resultCode == RESULT_OK && intent != null) { - // File name should be in Uri: - File filename = FileUriUtils.getFile(intent.getData()); - - if (filename.exists() && !filename.isDirectory()) { - // Open file in note editor - Intent i = new Intent(this, NoteEditor.class); - i.setAction(Intent.ACTION_VIEW); - i.setData(intent.getData()); - startActivity(i); } else { - Toast.makeText(this, R.string.file_not_found, - Toast.LENGTH_SHORT).show(); + mDecryptionFailed = true; + setProgressBarIndeterminateVisibility(false); } - } - break; - - /* - * case REQUEST_CODE_UNENCRYPT_NOTE: if (resultCode == RESULT_OK && data - * != null) { String[] decryptedTextArray = - * data.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); String - * decryptedText = decryptedTextArray[0]; String decryptedTitle = - * decryptedTextArray[1]; - * - * String uristring = data.getStringExtra(NotePadIntents.EXTRA_URI); - * - * Uri uri = null; if (uristring != null) { uri = Uri.parse(uristring); - * } else { Log.i(TAG, "Wrong extra uri"); Toast.makeText(this, - * "Encrypted information incomplete", Toast.LENGTH_SHORT).show(); - * return; } - * - * // Write this to content provider: - * - * ContentValues values = new ContentValues(); - * values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); - * values.put(Notes.TITLE, decryptedTitle); values.put(Notes.NOTE, - * decryptedText); values.put(Notes.ENCRYPTED, 0); - * - * //Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), - * id); Uri noteUri = getIntent().getData(); - * - * getContentResolver().update(uri, values, null, null); - * - * } else { setProgressBarIndeterminateVisibility(false); } break; - */ + break; + case REQUEST_CODE_OPEN: + if (resultCode == RESULT_OK && intent != null) { + // File name should be in Uri: + File filename = FileUriUtils.getFile(intent.getData()); + + if (filename.exists() && !filename.isDirectory()) { + // Open file in note editor + Intent i = new Intent(this, NoteEditor.class); + i.setAction(Intent.ACTION_VIEW); + i.setData(intent.getData()); + startActivity(i); + } else { + Toast.makeText(this, R.string.file_not_found, + Toast.LENGTH_SHORT).show(); + } + } + break; + + /* + case REQUEST_CODE_UNENCRYPT_NOTE: + if (resultCode == RESULT_OK && data != null) { + String[] decryptedTextArray = data.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); + String decryptedText = decryptedTextArray[0]; + String decryptedTitle = decryptedTextArray[1]; + + String uristring = data.getStringExtra(NotePadIntents.EXTRA_URI); + + Uri uri = null; + if (uristring != null) { + uri = Uri.parse(uristring); + } else { + Log.i(TAG, "Wrong extra uri"); + Toast.makeText(this, + "Encrypted information incomplete", + Toast.LENGTH_SHORT).show(); + return; + } + + // Write this to content provider: + + ContentValues values = new ContentValues(); + values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); + values.put(Notes.TITLE, decryptedTitle); + values.put(Notes.NOTE, decryptedText); + values.put(Notes.ENCRYPTED, 0); + + //Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), id); + Uri noteUri = getIntent().getData(); + + getContentResolver().update(uri, values, null, null); + + } else { + setProgressBarIndeterminateVisibility(false); + } + break; + */ } } private void saveFile(Uri uri, File file) { - if (debug) - Log.i(TAG, "Saving file: uri: " + uri + ", file: " + file); - Cursor c = getContentResolver().query(uri, - new String[] { Notes.ENCRYPTED, Notes.NOTE }, null, null, null); + if (debug) Log.i(TAG, "Saving file: uri: " + uri + ", file: " + file); + Cursor c = getContentResolver().query(uri, new String[] {Notes.ENCRYPTED, Notes.NOTE}, null, null, null); if (c != null && c.getCount() > 0) { c.moveToFirst(); @@ -1175,14 +1181,12 @@ private void saveFile(Uri uri, File file) { String note = c.getString(1); if (encrypted == 0) { // Save to file - if (debug) - Log.d(TAG, "Save unencrypted file."); + if (debug) Log.d(TAG, "Save unencrypted file."); writeToFile(file, note); } else { // decrypt first, then save to file - if (debug) - Log.d(TAG, "Save encrypted file."); + if (debug) Log.d(TAG, "Save encrypted file."); } } else { Log.e(TAG, "Error saving file: Uri not valid: " + uri); @@ -1195,8 +1199,8 @@ void writeToFile(File file, String text) { BufferedWriter out = new BufferedWriter(fstream); out.write(text); out.close(); - Toast.makeText(this, R.string.note_saved, Toast.LENGTH_SHORT) - .show(); + Toast.makeText(this, R.string.note_saved, + Toast.LENGTH_SHORT).show(); } catch (IOException e) { Toast.makeText(this, R.string.error_writing_file, Toast.LENGTH_SHORT).show(); @@ -1207,8 +1211,7 @@ void writeToFile(File file, String text) { BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { - if (debug) - Log.i(TAG, "flush decrypted data"); + if (debug) Log.i(TAG, "flush decrypted data"); NotesListCursor.flushDecryptedStringHashMap(); mAdapter.getCursor().requery(); } @@ -1216,14 +1219,19 @@ public void onReceive(Context context, Intent intent) { }; /* - * - * // Note: onKeyDown is never called, because the // list filter consumes - * the event before. - * - * @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if - * (keyCode == KeyEvent.KEYCODE_DEL) { // Delete the currently selected item - * (if any). Log.i(TAG, "Selected item: " + getSelectedItemId()); - * - * return true; } return false; } + + // Note: onKeyDown is never called, because the + // list filter consumes the event before. + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + // Delete the currently selected item (if any). + Log.i(TAG, "Selected item: " + getSelectedItemId()); + + return true; + } + return false; + } */ } diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java index 62dd9f5..5a32e39 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java @@ -30,21 +30,26 @@ public class NotesListCursor extends OpenMatrixCursor { /** * The columns we are interested in from the database */ - protected static final String[] PROJECTION_DB = new String[] { Notes._ID, // 0 - Notes.TITLE, // 1 - Notes.TAGS, // 2 - Notes.ENCRYPTED // 3 + protected static final String[] PROJECTION_DB = new String[] { + Notes._ID, // 0 + Notes.TITLE, // 1 + Notes.TAGS, // 2 + Notes.ENCRYPTED, // 3 + Notes.COLOR // 4 }; + /** * This cursors' columns */ - public static final String[] PROJECTION = new String[] { Notes._ID, // 0 - Notes.TITLE, // 1 - Notes.TAGS, // 2 - Notes.ENCRYPTED, // 3 - TITLE_DECRYPTED, // 4 - TAGS_DECRYPTED // 5 + public static final String[] PROJECTION = new String[] { + Notes._ID, // 0 + Notes.TITLE, // 1 + Notes.TAGS, // 2 + Notes.ENCRYPTED, // 3 + TITLE_DECRYPTED, // 4 + TAGS_DECRYPTED, // 5 + Notes.COLOR // 6 }; public static final int COLUMN_INDEX_ID = 0; @@ -55,6 +60,7 @@ public class NotesListCursor extends OpenMatrixCursor { /** Contains the encrypted title if it has not been decrypted yet */ public static final int COLUMN_INDEX_TITLE_ENCRYPTED = 4; public static final int COLUMN_INDEX_TAGS_ENCRYPTED = 5; + public static final int COLUMN_INDEX_COLOR = 4; static boolean mLoggedIn = false; @@ -63,11 +69,11 @@ public class NotesListCursor extends OpenMatrixCursor { Context mContext; Intent mIntent; - // OpenMatrixCursor mCursor; + //OpenMatrixCursor mCursor; /** - * A database cursor that corresponds to the encrypted data of the current - * cursor (that contains also decrypted information). + * A database cursor that corresponds to the encrypted data of + * the current cursor (that contains also decrypted information). */ Cursor mDbCursor; @@ -77,15 +83,13 @@ public class NotesListCursor extends OpenMatrixCursor { /** * Map encrypted titles to decrypted ones. */ - public static HashMap<String, String> mEncryptedStringHashMap = new HashMap<String, String>(); + public static HashMap<String,String> mEncryptedStringHashMap = new HashMap<String,String>(); /** - * List containing all encrypted strings. These are decrypted one at a time - * while idle. The list is synchronized because background threads may add - * items to it. + * List containing all encrypted strings. These are decrypted one at a time while idle. + * The list is synchronized because background threads may add items to it. */ - public static List<String> mEncryptedStringList = Collections - .synchronizedList(new LinkedList<String>()); + public static List<String> mEncryptedStringList = Collections.synchronizedList(new LinkedList<String>()); public boolean mContainsEncryptedStrings; @@ -98,6 +102,7 @@ public NotesListCursor(Context context, Intent intent) { } + // TODO: Replace new Handler() by mHandler from NotesList somehow. ContentObserver mContentObserver = new ContentObserver(new Handler()) { @@ -109,18 +114,17 @@ public boolean deliverSelfNotifications() { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - if (debug) - Log.d(TAG, "NoteListCursor changed: " + selfChange); + if (debug) Log.d(TAG, "NoteListCursor changed: " + selfChange); if (!mSuspendQueries) { - if (debug) - Log.d(TAG, "NoteListCursor requery()"); + if (debug) Log.d(TAG, "NoteListCursor requery()"); requery(); } } }; + @Override public boolean requery() { runQuery(mCurrentFilter, mSelectedTag); @@ -128,7 +132,8 @@ public boolean requery() { return super.requery(); } - /** + + /** * Return a new cursor with decrypted information. * * @param constraint @@ -139,22 +144,21 @@ public Cursor query(CharSequence constraint, String tag) { return cursor; } - /** + /** * Return a query with decrypted information on the current cursor. * * @param constraint */ private void runQuery(CharSequence constraint, String tag) { - // We have to query all items and return a new object, because notes may - // be encrypted. + // We have to query all items and return a new object, because notes may be encrypted. if (constraint != null) { mCurrentFilter = constraint.toString(); } else { mCurrentFilter = null; } - if (tag != null) { + if(tag != null) { mSelectedTag = tag; } else { mSelectedTag = null; @@ -165,17 +169,16 @@ private void runQuery(CharSequence constraint, String tag) { mDbCursor.close(); mDbCursor = null; } - mDbCursor = mContext.getContentResolver().query(mIntent.getData(), - PROJECTION_DB, null, null, - PreferenceActivity.getSortOrderFromPrefs(mContext)); + mDbCursor = mContext.getContentResolver().query(mIntent.getData(), PROJECTION_DB, + null, null, PreferenceActivity.getSortOrderFromPrefs(mContext)); + // Register content observer mDbCursor.registerContentObserver(mContentObserver); - if (debug) - Log.d(TAG, "Cursor count: " + mDbCursor.getCount()); + if (debug) Log.d(TAG, "Cursor count: " + mDbCursor.getCount()); - // mCursor = new OpenMatrixCursor(PROJECTION, dbcursor.getCount()); + //mCursor = new OpenMatrixCursor(PROJECTION, dbcursor.getCount()); reset(); mContainsEncryptedStrings = false; @@ -188,6 +191,7 @@ private void runQuery(CharSequence constraint, String tag) { String title = mDbCursor.getString(COLUMN_INDEX_TITLE); String tags = mDbCursor.getString(COLUMN_INDEX_TAGS); long encrypted = mDbCursor.getLong(COLUMN_INDEX_ENCRYPTED); + int color = mDbCursor.getInt(COLUMN_INDEX_COLOR); String titleEncrypted = ""; String tagsEncrypted = ""; @@ -199,12 +203,10 @@ private void runQuery(CharSequence constraint, String tag) { String titleDecrypted = mEncryptedStringHashMap.get(title); if (titleDecrypted != null) { - if (debug) - Log.d(TAG, "got title: " + titleDecrypted); + if (debug) Log.d(TAG, "got title: " + titleDecrypted); title = titleDecrypted; } else { - if (debug) - Log.d(TAG, "decrypt title later."); + if (debug) Log.d(TAG, "decrypt title later."); // decrypt later addForEncryption(title); @@ -218,12 +220,10 @@ private void runQuery(CharSequence constraint, String tag) { if (tags != null) { String tagsDecrypted = mEncryptedStringHashMap.get(tags); if (tagsDecrypted != null) { - if (debug) - Log.d(TAG, "got tags: " + tagsDecrypted); + if (debug) Log.d(TAG, "got tags: " + tagsDecrypted); tags = tagsDecrypted; } else { - if (debug) - Log.d(TAG, "decrypt tags later."); + if (debug) Log.d(TAG, "decrypt tags later."); // decrypt later addForEncryption(tags); @@ -236,8 +236,7 @@ private void runQuery(CharSequence constraint, String tag) { } if (!mLoggedIn) { - if (debug) - Log.d(TAG, "not logged in."); + if (debug) Log.d(TAG, "not logged in."); // suppress all decrypted output title = encryptedlabel; tags = ""; @@ -246,13 +245,11 @@ private void runQuery(CharSequence constraint, String tag) { boolean addrow = false; - if (TextUtils.isEmpty(mCurrentFilter) - && TextUtils.isEmpty(mSelectedTag)) { + if (TextUtils.isEmpty(mCurrentFilter) && TextUtils.isEmpty(mSelectedTag)) { // Add all rows if there is no filter. addrow = true; } else if (skipEncrypted) { - if (debug) - Log.d(TAG, "skipEncrypted)"); + if (debug) Log.d(TAG, "skipEncrypted)"); addrow = false; } else { // test the filter @@ -270,22 +267,20 @@ private void runQuery(CharSequence constraint, String tag) { List<String> tagList = new ArrayList<String>(); if (!TextUtils.isEmpty(tags)) { - for (String tagString : tags.split(",")) { - if (tagString.trim().length() != 0) { + for(String tagString: tags.split(",")) { + if(tagString.trim().length() != 0) { tagList.add(tagString.trim()); } } } - if (TextUtils.isEmpty(mCurrentFilter)) { + if ( TextUtils.isEmpty(mCurrentFilter) ) { addrow = tagList.contains(mSelectedTag.trim()); - } else if (TextUtils.isEmpty(mSelectedTag)) { - addrow = searchstring.contains(" " - + mCurrentFilter.toUpperCase()); + } else if ( TextUtils.isEmpty(mSelectedTag) ) { + addrow = searchstring.contains(" " + mCurrentFilter.toUpperCase()); } else { - addrow = searchstring.contains(" " - + mCurrentFilter.toUpperCase()) - && tagList.contains(mSelectedTag.trim()); + addrow = searchstring.contains(" " + mCurrentFilter.toUpperCase()) && + tagList.contains(mSelectedTag.trim()); } if (!addrow && encrypted != 0) { @@ -304,15 +299,14 @@ private void runQuery(CharSequence constraint, String tag) { mContainsEncryptedStrings = true; } - Object[] row = new Object[] { id, title, tags, encrypted, - titleEncrypted, tagsEncrypted }; + Object[] row = new Object[] {id, title, tags, encrypted, titleEncrypted, tagsEncrypted, color}; addRow(row); } } } public static void flushDecryptedStringHashMap() { - mEncryptedStringHashMap = new HashMap<String, String>(); + mEncryptedStringHashMap = new HashMap<String,String>(); mLoggedIn = false; } @@ -325,8 +319,7 @@ public static void addForEncryption(String encryptedString) { public static String getNextEncryptedString() { if (!NotesListCursor.mEncryptedStringList.isEmpty()) { - String encryptedString = NotesListCursor.mEncryptedStringList - .remove(0); + String encryptedString = NotesListCursor.mEncryptedStringList.remove(0); return encryptedString; } else { return null; @@ -335,29 +328,28 @@ public static String getNextEncryptedString() { @Override public void close() { - if (debug) - Log.d(TAG, "Close NotesListCursor"); + if (debug) Log.d(TAG, "Close NotesListCursor"); super.close(); } + @Override public void deactivate() { - if (debug) - Log.d(TAG, "Deactivate NotesListCursor"); + if (debug) Log.d(TAG, "Deactivate NotesListCursor"); if (mDbCursor != null) { mDbCursor.deactivate(); } super.deactivate(); } + @Override protected void finalize() { - if (debug) - Log.d(TAG, "Finalize NotesListCursor"); + if (debug) Log.d(TAG, "Finalize NotesListCursor"); if (mDbCursor != null) { mDbCursor.unregisterContentObserver(mContentObserver); - // mDbCursor.close(); + //mDbCursor.close(); mDbCursor.deactivate(); mDbCursor.close(); mDbCursor = null; @@ -366,4 +358,5 @@ protected void finalize() { super.finalize(); } + } diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java index 3558c51..c4b5171 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java @@ -12,13 +12,13 @@ public class NotesListCursorAdapter extends CursorAdapter { Context mContext; NotesListCursor mCursorUtils; + /** * Flag for slow list adapter. */ public boolean mBusy; - public NotesListCursorAdapter(Context context, Cursor c, - NotesListCursor cursorUtils) { + public NotesListCursorAdapter(Context context, Cursor c, NotesListCursor cursorUtils) { super(context, c); mContext = context; mCursorUtils = cursorUtils; @@ -33,10 +33,9 @@ public void bindView(View view, Context context, Cursor cursor) { String title = cursor.getString(NotesListCursor.COLUMN_INDEX_TITLE); String tags = cursor.getString(NotesListCursor.COLUMN_INDEX_TAGS); long encrypted = cursor.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); - String titleEncrypted = cursor - .getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); - String tagsEncrypted = cursor - .getString(NotesListCursor.COLUMN_INDEX_TAGS_ENCRYPTED); + String titleEncrypted = cursor.getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); + String tagsEncrypted = cursor.getString(NotesListCursor.COLUMN_INDEX_TAGS_ENCRYPTED); + int color = cursor.getInt(NotesListCursor.COLUMN_INDEX_COLOR + 2); nliv.setEncrypted(encrypted); @@ -44,58 +43,83 @@ public void bindView(View view, Context context, Cursor cursor) { nliv.setTags(tags); nliv.mTitleEncrypted = titleEncrypted; nliv.mTagsEncrypted = tagsEncrypted; + nliv.setColor(color); + /* - * if (encrypted == 0) { // Not encrypted: nliv.setTitle(title); - * nliv.setTags(tags); // Null tag means the view has the correct data - * nliv.setTag(null); } else { // encrypted String decrypted = - * mTitleHashMap.get(title); if (decrypted != null) { - * nliv.setTitle(decrypted); nliv.setTags(tags); // Null tag means the - * view has the correct data nliv.setTag(null); } else { - * nliv.setTitle(mContext.getString(R.string.encrypted)); - * nliv.setTags(tags); // Non-null tag means the view still needs to - * load it's data // Tag contains a pointer to a string with the - * encrypted title. nliv.setTag(title); } /* if (!mBusy) { - * nliv.setTitle("set"); nliv.setTitle("wow"); // Null tag means the - * view has the correct data nliv.setTag(null); } else { - * nliv.setTitle(mContext.getString(R.string.encrypted)); - * nliv.setTags(tags); // Non-null tag means the view still needs to - * load it's data nliv.setTag(this); } / } + if (encrypted == 0) { + // Not encrypted: + nliv.setTitle(title); + nliv.setTags(tags); + // Null tag means the view has the correct data + nliv.setTag(null); + } else { + // encrypted + String decrypted = mTitleHashMap.get(title); + if (decrypted != null) { + nliv.setTitle(decrypted); + nliv.setTags(tags); + // Null tag means the view has the correct data + nliv.setTag(null); + } else { + nliv.setTitle(mContext.getString(R.string.encrypted)); + nliv.setTags(tags); + // Non-null tag means the view still needs to load it's data + // Tag contains a pointer to a string with the encrypted title. + nliv.setTag(title); + } + /* + if (!mBusy) { + nliv.setTitle("set"); + nliv.setTitle("wow"); + // Null tag means the view has the correct data + nliv.setTag(null); + } else { + nliv.setTitle(mContext.getString(R.string.encrypted)); + nliv.setTags(tags); + // Non-null tag means the view still needs to load it's data + nliv.setTag(this); + } + * / + } */ } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return new NotesListItemView(context); - } + } + /* - * @Override public Filter getFilter() { Log.i(TAG, "Request filter"); - * - * return super.getFilter(); } + @Override + public Filter getFilter() { + Log.i(TAG, "Request filter"); + + return super.getFilter(); + } */ /* - * @Override public CharSequence convertToString(Cursor cursor) { //return - * super.convertToString(cursor); - * - * Log.i(TAG, "convertToString" + cursor.getPosition() + " / " + - * cursor.getCount()); - * - * return cursor.getString(NotesList.COLUMN_INDEX_TITLE); } + @Override + public CharSequence convertToString(Cursor cursor) { + //return super.convertToString(cursor); + + Log.i(TAG, "convertToString" + cursor.getPosition() + " / " + cursor.getCount()); + + return cursor.getString(NotesList.COLUMN_INDEX_TITLE); + } */ public Cursor runQueryOnBackgroundThread(CharSequence constraint, String tag) { - // Log.i(TAG, "runQueryOnBackgroundThread " + constraint + ", " + - // mIntent.getData()); + //Log.i(TAG, "runQueryOnBackgroundThread " + constraint + ", " + mIntent.getData()); + /* - * Cursor cursor = - * mContext.getContentResolver().query(mIntent.getData(), - * NotesList.PROJECTION, "(" + Notes.TITLE + " like '" + - * constraint.toString() + "%' ) or (" + Notes.TITLE + " like '% " + - * constraint.toString() + "%' )", new String[] { }, - * Notes.DEFAULT_SORT_ORDER); + Cursor cursor = mContext.getContentResolver().query(mIntent.getData(), NotesList.PROJECTION, + "(" + Notes.TITLE + " like '" + constraint.toString() + "%' ) or (" + + Notes.TITLE + " like '% " + constraint.toString() + "%' )", + new String[] { }, Notes.DEFAULT_SORT_ORDER); */ Cursor cursor = mCursorUtils.query(constraint, tag); @@ -103,4 +127,5 @@ public Cursor runQueryOnBackgroundThread(CharSequence constraint, String tag) { return cursor; } + } diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java index 628f5bf..be0e59f 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java @@ -4,6 +4,8 @@ import org.openintents.notepad.R; import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; @@ -25,6 +27,7 @@ public class NotesListItemView extends LinearLayout { protected String mTitleEncrypted; protected String mTagsEncrypted; + public NotesListItemView(Context context) { super(context); mContext = context; @@ -33,26 +36,33 @@ public NotesListItemView(Context context) { LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.noteslist_item, this, true); + inflater.inflate( + R.layout.noteslist_item, this, true); mTitle = (MarqueeTextView) findViewById(R.id.title); mTags = (TextView) findViewById(R.id.info); mStatus = (ImageView) findViewById(R.id.status); } + + @Override public boolean hasFocus() { // TODO Auto-generated method stub - if (PreferenceActivity.getMarqueeFromPrefs(mContext) == true) { + if(PreferenceActivity.getMarqueeFromPrefs(mContext)==true) { mTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE); mTitle.setMarquee(true); - } else { + } + else + { mTitle.setEllipsize(TextUtils.TruncateAt.END); mTitle.setMarquee(false); } return super.hasFocus(); } + + /** * Convenience method to set the title of a NewsView */ @@ -76,4 +86,29 @@ public void setEncrypted(long encrypted) { mStatus.setImageBitmap(null); } } + + + + public void setColor(int color) { + Resources res = this.getResources(); + Drawable d = res.getDrawable(R.drawable.note_item_bg_yellow); + switch(color) { + case R.color.lightBabyBlue: + d = res.getDrawable(R.drawable.note_item_bg_blue); + break; + case R.color.lightGray: + d = res.getDrawable(R.drawable.note_item_bg_grey); + break; + case R.color.lightGreen: + d = res.getDrawable(R.drawable.note_item_bg_green); + break; + case R.color.lightPink: + d = res.getDrawable(R.drawable.note_item_bg_pink); + break; + default: + break; + } + + mTitle.setBackgroundDrawable(d); + } } diff --git a/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java b/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java index 2a1d249..2144219 100644 --- a/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java +++ b/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java @@ -1,4 +1,6 @@ package org.openintents.notepad.wrappers; +import org.openintents.notepad.R; + import android.app.ActionBar; import android.app.Activity; @@ -6,33 +8,34 @@ public class WrapActionBar { private ActionBar mInstance; - + static { try { Class.forName("android.app.ActionBar"); - } catch (Exception ex) { + } catch (Exception ex){ throw new RuntimeException(ex); } } - + /* calling here forces class initialization */ public static void checkAvailable() { + } - - public WrapActionBar(Activity a) { + + public WrapActionBar(Activity a){ mInstance = a.getActionBar(); } - - public void setDisplayHomeAsUpEnabled(boolean b) { + + public void setDisplayHomeAsUpEnabled(boolean b){ mInstance.setDisplayHomeAsUpEnabled(b); } - - public void setHomeButtonEnabled(boolean b) { + + public void setHomeButtonEnabled(boolean b){ mInstance.setHomeButtonEnabled(b); } - + // show an icon in the actionbar if there is room for it. - public static void showIfRoom(MenuItem item) { + public static void showIfRoom(MenuItem item){ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } } From e038c3fa61dae159d7182eb9b21efed1af5f25dc Mon Sep 17 00:00:00 2001 From: Benedikt Elser <boun@gmx.de> Date: Mon, 25 Feb 2013 13:04:47 +0100 Subject: [PATCH 3/8] Storing a resource ID is probably not a good idea ;) --- .../org/openintents/notepad/NoteEditor.java | 37 ++++++++++++++++--- .../notepad/noteslist/NotesListItemView.java | 13 +++++-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/NotePad/src/org/openintents/notepad/NoteEditor.java b/NotePad/src/org/openintents/notepad/NoteEditor.java index 228eebc..02756ac 100644 --- a/NotePad/src/org/openintents/notepad/NoteEditor.java +++ b/NotePad/src/org/openintents/notepad/NoteEditor.java @@ -208,6 +208,12 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static int sSelectionStart = 0; private static int sSelectionStop = 0; + private static final int BLUE = 1; + private static final int GREEN = 2; + private static final int GREY = 3; + private static final int PINK = 4; + private static final int YELLOW = 5; + private String mFileContent; @@ -1403,19 +1409,19 @@ public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.editor_color_yellow: - setNoteColor((int)R.color.lightYellow); + setNoteColor(YELLOW); break; case R.id.editor_color_pink: - setNoteColor((int)R.color.lightPink); + setNoteColor(PINK); break; case R.id.editor_color_blue: - setNoteColor((int)R.color.lightBabyBlue); + setNoteColor(BLUE); break; case R.id.editor_color_green: - setNoteColor((int)R.color.lightGreen); + setNoteColor(GREEN); break; case R.id.editor_color_gray: - setNoteColor((int)R.color.lightGray); + setNoteColor(GREY); break; default: break; @@ -1430,10 +1436,29 @@ private void shareNote() { } protected void setNoteColor(int color) { + int id = (int)R.color.lightYellow; Resources res = getResources(); LinearLayout c = (LinearLayout) findViewById(R.id.editor_color); c.setVisibility(View.GONE); - mText.setBackgroundDrawable(res.getDrawable(color)); + + switch (color) { + case BLUE: + id = (int)R.color.lightBabyBlue; + break; + case GREEN: + id = (int)R.color.lightGreen; + break; + case PINK: + id = (int)R.color.lightPink; + break; + case GREY: + id = (int)R.color.lightGray; + break; + default: + break; + } + + mText.setBackgroundDrawable(res.getDrawable(id)); if (color == mColor) return; diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java index be0e59f..26f1cdd 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java @@ -27,6 +27,11 @@ public class NotesListItemView extends LinearLayout { protected String mTitleEncrypted; protected String mTagsEncrypted; + private static final int BLUE = 1; + private static final int GREEN = 2; + private static final int GREY = 3; + private static final int PINK = 4; + private static final int YELLOW = 5; public NotesListItemView(Context context) { super(context); @@ -93,16 +98,16 @@ public void setColor(int color) { Resources res = this.getResources(); Drawable d = res.getDrawable(R.drawable.note_item_bg_yellow); switch(color) { - case R.color.lightBabyBlue: + case BLUE: d = res.getDrawable(R.drawable.note_item_bg_blue); break; - case R.color.lightGray: + case GREY: d = res.getDrawable(R.drawable.note_item_bg_grey); break; - case R.color.lightGreen: + case GREEN: d = res.getDrawable(R.drawable.note_item_bg_green); break; - case R.color.lightPink: + case PINK: d = res.getDrawable(R.drawable.note_item_bg_pink); break; default: From a047838d0e29efd148ae5acdfd64d75afd2c9ed4 Mon Sep 17 00:00:00 2001 From: Benedikt Elser <boun@gmx.de> Date: Mon, 25 Feb 2013 14:36:07 +0100 Subject: [PATCH 4/8] Wrap Note in a ScrollView, vastly improve perceived performance --- NotePad/res/layout/note_editor.xml | 33 ++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/NotePad/res/layout/note_editor.xml b/NotePad/res/layout/note_editor.xml index 39c390d..494c006 100644 --- a/NotePad/res/layout/note_editor.xml +++ b/NotePad/res/layout/note_editor.xml @@ -20,17 +20,28 @@ android:orientation="vertical" android:background="@android:color/white" android:layout_width="fill_parent" - android:layout_height="fill_parent"> - -<view android:id="@+id/note" - class="org.openintents.notepad.NoteEditor$LinedEditText" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:padding="5dip" - android:scrollbars="vertical" - android:fadingEdge="vertical" - android:gravity="top" - android:capitalize="sentences"/> + android:layout_height="match_parent"> + + <ScrollView + android:id="@+id/scroll" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:fillViewport="true" + android:fadingEdge="none"> + <view android:id="@+id/note" + class="org.openintents.notepad.NoteEditor$LinedEditText" + android:padding="5dip" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:background="@color/darkPink" + android:fadingEdge="none" + android:scrollbars="vertical|horizontal" + android:gravity="top" + android:autoText="false" + android:capitalize="none" + /> + </ScrollView> <LinearLayout android:id="@+id/editor_color" android:clickable="true" From 6b3b5d56739faa73eff9259dbdd24d97a4c12d47 Mon Sep 17 00:00:00 2001 From: Benedikt Elser <boun@gmx.de> Date: Mon, 25 Feb 2013 18:56:42 +0100 Subject: [PATCH 5/8] I devote this commit to Eclipse. Most of it is reverting indent and formating changes done by eclipse. The rest is cleaning up comments. --- NotePad/res/drawable/header_bg_brown.xml | 11 +- NotePad/res/drawable/note_item_bg_blue.xml | 10 +- NotePad/res/drawable/note_item_bg_green.xml | 10 +- NotePad/res/drawable/note_item_bg_grey.xml | 10 +- NotePad/res/drawable/note_item_bg_pink.xml | 10 +- NotePad/res/drawable/note_item_bg_yellow.xml | 10 +- NotePad/res/layout/note_editor.xml | 4 +- NotePad/res/layout/noteslist.xml | 2 +- NotePad/res/layout/noteslist_item.xml | 4 +- NotePad/res/values/colors.xml | 7 +- NotePad/res/values/strings.xml | 2 +- .../org/openintents/notepad/NoteEditor.java | 1326 +++++++++-------- .../src/org/openintents/notepad/NotePad.java | 98 +- .../openintents/notepad/NotePadProvider.java | 270 ++-- .../notepad/noteslist/NotesList.java | 774 +++++----- .../notepad/noteslist/NotesListCursor.java | 130 +- .../noteslist/NotesListCursorAdapter.java | 103 +- .../notepad/noteslist/NotesListItemView.java | 29 +- .../notepad/wrappers/WrapActionBar.java | 25 +- 19 files changed, 1433 insertions(+), 1402 deletions(-) diff --git a/NotePad/res/drawable/header_bg_brown.xml b/NotePad/res/drawable/header_bg_brown.xml index 4e0cbda..303abb2 100644 --- a/NotePad/res/drawable/header_bg_brown.xml +++ b/NotePad/res/drawable/header_bg_brown.xml @@ -1,11 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- selector - xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:drawable="@drawable/biaoqian_huang" /> - -</selector --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item> @@ -19,5 +12,5 @@ android:color="@color/darkBrown" /> </shape> </item> - - </selector> + +</selector> diff --git a/NotePad/res/drawable/note_item_bg_blue.xml b/NotePad/res/drawable/note_item_bg_blue.xml index b74f813..c5fb359 100644 --- a/NotePad/res/drawable/note_item_bg_blue.xml +++ b/NotePad/res/drawable/note_item_bg_blue.xml @@ -1,11 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- selector - xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:drawable="@drawable/biaoqian_huang" /> - -</selector --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > @@ -34,5 +27,4 @@ android:radius="3dp" /> </shape> </item> - - </selector> +</selector> diff --git a/NotePad/res/drawable/note_item_bg_green.xml b/NotePad/res/drawable/note_item_bg_green.xml index e851a61..175c958 100644 --- a/NotePad/res/drawable/note_item_bg_green.xml +++ b/NotePad/res/drawable/note_item_bg_green.xml @@ -1,11 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- selector - xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:drawable="@drawable/biaoqian_huang" /> - -</selector --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > @@ -34,5 +27,4 @@ android:radius="3dp" /> </shape> </item> - - </selector> +</selector> diff --git a/NotePad/res/drawable/note_item_bg_grey.xml b/NotePad/res/drawable/note_item_bg_grey.xml index bdf7bc3..33d5f25 100644 --- a/NotePad/res/drawable/note_item_bg_grey.xml +++ b/NotePad/res/drawable/note_item_bg_grey.xml @@ -1,11 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- selector - xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:drawable="@drawable/biaoqian_huang" /> - -</selector --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > @@ -34,5 +27,4 @@ android:radius="3dp" /> </shape> </item> - - </selector> +</selector> diff --git a/NotePad/res/drawable/note_item_bg_pink.xml b/NotePad/res/drawable/note_item_bg_pink.xml index ed5a5b9..5330abc 100644 --- a/NotePad/res/drawable/note_item_bg_pink.xml +++ b/NotePad/res/drawable/note_item_bg_pink.xml @@ -1,11 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- selector - xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:drawable="@drawable/biaoqian_huang" /> - -</selector --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > @@ -34,5 +27,4 @@ android:radius="3dp" /> </shape> </item> - - </selector> +</selector> diff --git a/NotePad/res/drawable/note_item_bg_yellow.xml b/NotePad/res/drawable/note_item_bg_yellow.xml index 957c339..fbe4a36 100644 --- a/NotePad/res/drawable/note_item_bg_yellow.xml +++ b/NotePad/res/drawable/note_item_bg_yellow.xml @@ -1,11 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- selector - xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:state_pressed="true" android:drawable="@drawable/biaoqian_huaguo" /> - <item android:drawable="@drawable/biaoqian_huang" /> - -</selector --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > @@ -34,5 +27,4 @@ android:radius="3dp" /> </shape> </item> - - </selector> +</selector> diff --git a/NotePad/res/layout/note_editor.xml b/NotePad/res/layout/note_editor.xml index 494c006..209c3c5 100644 --- a/NotePad/res/layout/note_editor.xml +++ b/NotePad/res/layout/note_editor.xml @@ -19,7 +19,7 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="@android:color/white" - android:layout_width="fill_parent" + android:layout_width="fill_parent" android:layout_height="match_parent"> <ScrollView @@ -48,7 +48,7 @@ android:orientation="horizontal" android:layout_width="290.0dp" android:layout_height="wrap_content" android:layout_gravity="top|center" android:gravity="center" - android:layout_marginTop="70.0dp" + android:layout_marginTop="70.0dp" android:background="@drawable/zhengwen_xuanyanse" android:visibility="gone"> <ImageView android:id="@+id/editor_color_yellow" diff --git a/NotePad/res/layout/noteslist.xml b/NotePad/res/layout/noteslist.xml index 052d60b..4fb0c57 100644 --- a/NotePad/res/layout/noteslist.xml +++ b/NotePad/res/layout/noteslist.xml @@ -37,7 +37,7 @@ find it --> <ListView android:id="@android:id/list" android:layout_width="fill_parent" - android:layout_height="fill_parent" + android:layout_height="fill_parent" android:fastScrollEnabled="true" android:drawSelectorOnTop="false"/> diff --git a/NotePad/res/layout/noteslist_item.xml b/NotePad/res/layout/noteslist_item.xml index b703ed1..ae3b52d 100644 --- a/NotePad/res/layout/noteslist_item.xml +++ b/NotePad/res/layout/noteslist_item.xml @@ -35,8 +35,8 @@ android:layout_width="fill_parent" android:drawablePadding="1dp" android:textAppearance="?android:attr/textAppearanceLarge" - android:singleLine="true" - android:background="@drawable/note_item_bg_yellow" + android:singleLine="true" + android:background="@drawable/note_item_bg_yellow" android:ellipsize="end" android:scrollHorizontally="true" android:textColor="#ff4b4b4b" diff --git a/NotePad/res/values/colors.xml b/NotePad/res/values/colors.xml index 4ed7ef9..d8919cc 100644 --- a/NotePad/res/values/colors.xml +++ b/NotePad/res/values/colors.xml @@ -12,16 +12,15 @@ <color name="lightBrown">#825f3f</color> <color name="darkBrown">#5b371d</color> - + <color name="lightBabyBlue">#ddf2ff</color> <color name="darkBabyBlue">#ddf2ff</color> <color name="darkestBabyBlue">#acd6f1</color> - - + <color name="lightPink">#ffeded</color> <color name="darkPink">#ffeded</color> <color name="darkestPink">#d1c2c2</color> - + <color name="lightGreen">#eafecf</color> <color name="darkGreen">#cfe08a</color> <color name="darkestGreen">#b3c665</color> diff --git a/NotePad/res/values/strings.xml b/NotePad/res/values/strings.xml index 63a324f..78880f1 100644 --- a/NotePad/res/values/strings.xml +++ b/NotePad/res/values/strings.xml @@ -69,7 +69,7 @@ <string name="menu_share">Share</string> <string name="menu_color">Color</string> - + <string name="empty_note">Empty note</string> <string name="share_not_available">No application available for sharing.</string> diff --git a/NotePad/src/org/openintents/notepad/NoteEditor.java b/NotePad/src/org/openintents/notepad/NoteEditor.java index 02756ac..76e7860 100644 --- a/NotePad/src/org/openintents/notepad/NoteEditor.java +++ b/NotePad/src/org/openintents/notepad/NoteEditor.java @@ -98,9 +98,10 @@ import android.widget.Toast; /** - * A generic activity for editing a note in a database. This can be used - * either to simply view a note {@link Intent#ACTION_VIEW}, view and edit a note - * {@link Intent#ACTION_EDIT}, or create a new note {@link Intent#ACTION_INSERT}. + * A generic activity for editing a note in a database. This can be used either + * to simply view a note {@link Intent#ACTION_VIEW}, view and edit a note + * {@link Intent#ACTION_EDIT}, or create a new note {@link Intent#ACTION_INSERT} + * . */ public class NoteEditor extends Activity implements ThemeDialogListener { private static final String TAG = "NoteEditor"; @@ -109,16 +110,15 @@ public class NoteEditor extends Activity implements ThemeDialogListener { /** * Standard projection for the interesting columns of a normal note. */ - private static final String[] PROJECTION = new String[] { - Notes._ID, // 0 - Notes.NOTE, // 1 - Notes.TAGS, // 2 - Notes.ENCRYPTED, // 3 - Notes.THEME, // 4 - Notes.SELECTION_START, // 5 - Notes.SELECTION_END, // 6 - Notes.SCROLL_POSITION, // 7 - Notes.COLOR, // 7 + private static final String[] PROJECTION = new String[] { Notes._ID, // 0 + Notes.NOTE, // 1 + Notes.TAGS, // 2 + Notes.ENCRYPTED, // 3 + Notes.THEME, // 4 + Notes.SELECTION_START, // 5 + Notes.SELECTION_END, // 6 + Notes.SCROLL_POSITION, // 7 + Notes.COLOR, // 7 }; /** The index of the note column */ private static final int COLUMN_INDEX_ID = 0; @@ -131,7 +131,6 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final int COLUMN_INDEX_SCROLL_POSITION = 7; private static final int COLUMN_INDEX_COLOR = 8; - // This is our state data that is stored when freezing. private static final String BUNDLE_ORIGINAL_CONTENT = "original_content"; private static final String BUNDLE_UNDO_REVERT = "undo_revert"; @@ -139,13 +138,12 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final String BUNDLE_URI = "uri"; private static final String BUNDLE_SELECTION_START = "selection_start"; private static final String BUNDLE_SELECTION_STOP = "selection_stop"; - // private static final String BUNDLE_FILENAME = "filename"; + // private static final String BUNDLE_FILENAME = "filename"; private static final String BUNDLE_FILE_CONTENT = "file_content"; private static final String BUNDLE_APPLY_TEXT = "apply_text"; private static final String BUNDLE_APPLY_TEXT_BEFORE = "apply_text_before"; private static final String BUNDLE_APPLY_TEXT_AFTER = "apply_text_after"; - // Identifiers for our menu items. private static final int MENU_REVERT = Menu.FIRST; private static final int MENU_DISCARD = Menu.FIRST + 1; @@ -161,7 +159,7 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final int MENU_WORD_COUNT = Menu.FIRST + 11; private static final int MENU_COLOR = Menu.FIRST + 12; - //private static final int REQUEST_CODE_ENCRYPT = 1; + // private static final int REQUEST_CODE_ENCRYPT = 1; private static final int REQUEST_CODE_DECRYPT = 2; private static final int REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE = 3; private static final int REQUEST_CODE_SAVE_AS = 4; @@ -175,8 +173,15 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private static final int DIALOG_UNSAVED_CHANGES = 1; private static final int DIALOG_THEME = 2; private static final int DIALOG_DELETE = 3; - - private static final int GROUP_ID_TEXT_SELECTION_ALTERNATIVE = 1234; // some number that must not collide with others + + private static final int GROUP_ID_TEXT_SELECTION_ALTERNATIVE = 1234; // some + // number + // that + // must + // not + // collide + // with + // others private int mState; private boolean mNoteOnly = false; @@ -201,8 +206,7 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private int mColor = -1; /** - * static string for hack. - * Only used for configuration changes. + * static string for hack. Only used for configuration changes. */ private static String sDecryptedText = null; private static int sSelectionStart = 0; @@ -217,7 +221,7 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private String mFileContent; - // private String mTags; + // private String mTags; private String mTheme; @@ -227,10 +231,10 @@ public class NoteEditor extends Activity implements ThemeDialogListener { public boolean mTextUpperCaseFont; public int mTextColor; public int mBackgroundPadding; - + /** - * Which features are supported (which columns are available in the database)? - * Everything is supported by default. + * Which features are supported (which columns are available in the + * database)? Everything is supported by default. */ private boolean hasNoteColumn = true; private boolean hasTagsColumn = true; @@ -241,29 +245,28 @@ public class NoteEditor extends Activity implements ThemeDialogListener { private boolean hasSelection_endColumn = true; /** - * Lines mode: - * 0..no line. - * 2..show lines only where there is text (padding width). - * 3..show lines only where there is text (full width). - * 4..show lines for whole page (padding width). - * 5..show lines for whole page (full width). + * Lines mode: 0..no line. 2..show lines only where there is text (padding + * width). 3..show lines only where there is text (full width). 4..show + * lines for whole page (padding width). 5..show lines for whole page (full + * width). */ public static int mLinesMode; public static int mLinesColor; - + private static boolean mActionBarAvailable; - + static { try { WrapActionBar.checkAvailable(); mActionBarAvailable = true; - } catch(Throwable t){ + } catch (Throwable t) { mActionBarAvailable = false; } } - + /** - * A custom EditText that draws lines between each line of text that is displayed. + * A custom EditText that draws lines between each line of text that is + * displayed. */ public static class LinedEditText extends EditText { private Rect mRect; @@ -278,8 +281,8 @@ public LinedEditText(Context context, AttributeSet attrs) { mPaint.setStyle(Paint.Style.STROKE); } - //@Override - protected void onDraws(Canvas canvas) { + @Override + protected void onDraw(Canvas canvas) { boolean fullWidth = (mLinesMode & 1) == 1; boolean textlines = (mLinesMode & 2) == 2; boolean pagelines = (mLinesMode & 4) == 4; @@ -305,18 +308,20 @@ protected void onDraws(Canvas canvas) { left = getLeft(); right = getRight(); } - canvas.drawLine(left, baseline + 1, right, baseline + 1, paint); + canvas.drawLine(left, baseline + 1, right, baseline + 1, + paint); } if (pagelines) { // Fill the rest of the page with lines for (int i = count; i < page_size; i++) { baseline += line_height; - canvas.drawLine(left, baseline + 1, right, baseline + 1, paint); + canvas.drawLine(left, baseline + 1, right, + baseline + 1, paint); } } - } - - //super.onDraw(canvas); + } + + super.onDraw(canvas); } } @@ -324,9 +329,10 @@ protected void onDraws(Canvas canvas) { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (debug) Log.d(TAG, "onCreate()"); + if (debug) + Log.d(TAG, "onCreate()"); - if(getIntent().getAction().equals(Intent.ACTION_CREATE_SHORTCUT)) { + if (getIntent().getAction().equals(Intent.ACTION_CREATE_SHORTCUT)) { createShortcut(); return; } @@ -339,12 +345,13 @@ protected void onCreate(Bundle savedInstanceState) { // Usually, sDecryptedText == null. mDecryptedText = sDecryptedText; if (sDecryptedText != null) { - // we use the text right now, + // we use the text right now, // so don't encrypt the text anymore. EncryptActivity.cancelEncrypt(); if (EncryptActivity.getPendingEncryptActivities() == 0) { - if (debug) Log.d(TAG, "sDecryptedText = null"); + if (debug) + Log.d(TAG, "sDecryptedText = null"); // no more encrypt activies will be called sDecryptedText = null; } @@ -356,26 +363,31 @@ protected void onCreate(Bundle savedInstanceState) { // If an instance of this activity had previously stopped, we can // get the original text it started with. if (savedInstanceState != null) { - mOriginalContent = savedInstanceState.getString(BUNDLE_ORIGINAL_CONTENT); + mOriginalContent = savedInstanceState + .getString(BUNDLE_ORIGINAL_CONTENT); mUndoRevert = savedInstanceState.getString(BUNDLE_UNDO_REVERT); mState = savedInstanceState.getInt(BUNDLE_STATE); mUri = Uri.parse(savedInstanceState.getString(BUNDLE_URI)); mSelectionStart = savedInstanceState.getInt(BUNDLE_SELECTION_START); mSelectionStop = savedInstanceState.getInt(BUNDLE_SELECTION_STOP); mFileContent = savedInstanceState.getString(BUNDLE_FILE_CONTENT); - if (mApplyText == null && mApplyTextBefore == null && mApplyTextAfter == null) { - // Only read values if they had not been set by onActivityResult() yet: + if (mApplyText == null && mApplyTextBefore == null + && mApplyTextAfter == null) { + // Only read values if they had not been set by + // onActivityResult() yet: mApplyText = savedInstanceState.getString(BUNDLE_APPLY_TEXT); - mApplyTextBefore = savedInstanceState.getString(BUNDLE_APPLY_TEXT_BEFORE); - mApplyTextAfter = savedInstanceState.getString(BUNDLE_APPLY_TEXT_AFTER); + mApplyTextBefore = savedInstanceState + .getString(BUNDLE_APPLY_TEXT_BEFORE); + mApplyTextAfter = savedInstanceState + .getString(BUNDLE_APPLY_TEXT_AFTER); } } else { // Do some setup based on the action being performed. final Intent intent = getIntent(); - final String action = intent.getAction(); - if (Intent.ACTION_EDIT.equals(action) || Intent.ACTION_VIEW.equals(action)) { + if (Intent.ACTION_EDIT.equals(action) + || Intent.ACTION_VIEW.equals(action)) { // Requested to edit: set that state, and the data being edited. mState = STATE_EDIT; mUri = intent.getData(); @@ -385,75 +397,65 @@ protected void onCreate(Bundle savedInstanceState) { // Load the file into a new note. mFileContent = readFile(FileUriUtils.getFile(mUri)); - } else if ( ! mUri.getAuthority().equals(NotePad.AUTHORITY)) { + } else if (!mUri.getAuthority().equals(NotePad.AUTHORITY)) { // Note a notepad note. Treat slightly differently. // (E.g. a note from OI Shopping List) mState = STATE_EDIT_EXTERNAL_NOTE; } /* - if (mUri.getScheme().equals("file")) { - // Load the file into a new note. - - mFilename = FileUriUtils.getFilename(mUri); - - String text = readFile(FileUriUtils.getFile(mUri)); - - if (text == null) { - Log.e(TAG, "Error reading file"); - finish(); - return; - } - - - - // Let's check whether the exactly same note already exists or not: - Cursor c = getContentResolver().query(Notes.CONTENT_URI, - new String[] {Notes._ID}, - Notes.NOTE + " = ?", new String[] {text}, null); - if (c != null && c.getCount() > 0) { - // Same note exists already: - c.moveToFirst(); - long id = c.getLong(0); - mUri = ContentUris.withAppendedId(Notes.CONTENT_URI, id); - } else { - - // Add new note - // Requested to insert: set that state, and create a new entry - // in the container. - mState = STATE_INSERT; - ContentValues values = new ContentValues(); - values.put(Notes.NOTE, text); - mUri = getContentResolver().insert(Notes.CONTENT_URI, values); - intent.setAction(Intent.ACTION_EDIT); - intent.setData(mUri); - setIntent(intent); - - // If we were unable to create a new note, then just finish - // this activity. A RESULT_CANCELED will be sent back to the - // original activity if they requested a result. - if (mUri == null) { - Log.e(TAG, "Failed to insert new note into " + getIntent().getData()); - finish(); - return; - } - - // The new entry was created, so assume all will end well and - // set the result to be returned. - //setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); - setResult(RESULT_OK, intent); - } - - }*/ - } else if (Intent.ACTION_INSERT.equals(action) || Intent.ACTION_SEND.equals(action)) { + * if (mUri.getScheme().equals("file")) { // Load the file into + * a new note. + * + * mFilename = FileUriUtils.getFilename(mUri); + * + * String text = readFile(FileUriUtils.getFile(mUri)); + * + * if (text == null) { Log.e(TAG, "Error reading file"); + * finish(); return; } + * + * + * + * // Let's check whether the exactly same note already exists + * or not: Cursor c = + * getContentResolver().query(Notes.CONTENT_URI, new String[] + * {Notes._ID}, Notes.NOTE + " = ?", new String[] {text}, null); + * if (c != null && c.getCount() > 0) { // Same note exists + * already: c.moveToFirst(); long id = c.getLong(0); mUri = + * ContentUris.withAppendedId(Notes.CONTENT_URI, id); } else { + * + * // Add new note // Requested to insert: set that state, and + * create a new entry // in the container. mState = + * STATE_INSERT; ContentValues values = new ContentValues(); + * values.put(Notes.NOTE, text); mUri = + * getContentResolver().insert(Notes.CONTENT_URI, values); + * intent.setAction(Intent.ACTION_EDIT); intent.setData(mUri); + * setIntent(intent); + * + * // If we were unable to create a new note, then just finish + * // this activity. A RESULT_CANCELED will be sent back to the + * // original activity if they requested a result. if (mUri == + * null) { Log.e(TAG, "Failed to insert new note into " + + * getIntent().getData()); finish(); return; } + * + * // The new entry was created, so assume all will end well and + * // set the result to be returned. //setResult(RESULT_OK, (new + * Intent()).setAction(mUri.toString())); setResult(RESULT_OK, + * intent); } + * + * } + */ + } else if (Intent.ACTION_INSERT.equals(action) + || Intent.ACTION_SEND.equals(action)) { // Use theme of most recently modified note: ContentValues values = new ContentValues(1); String theme = getMostRecentlyUsedTheme(); values.put(Notes.THEME, theme); - String tags = intent.getStringExtra(NotepadInternalIntents.EXTRA_TAGS); + String tags = intent + .getStringExtra(NotepadInternalIntents.EXTRA_TAGS); values.put(Notes.TAGS, tags); - - if(mText != null) { + + if (mText != null) { values.put(Notes.SELECTION_START, mText.getSelectionStart()); values.put(Notes.SELECTION_END, mText.getSelectionEnd()); } @@ -462,54 +464,59 @@ protected void onCreate(Bundle savedInstanceState) { // in the container. mState = STATE_INSERT; /* - intent.setAction(Intent.ACTION_EDIT); - intent.setData(mUri); - setIntent(intent); + * intent.setAction(Intent.ACTION_EDIT); intent.setData(mUri); + * setIntent(intent); */ - - if(Intent.ACTION_SEND.equals(action)) { - values.put(Notes.NOTE, getIntent().getStringExtra(Intent.EXTRA_TEXT)); - mUri = getContentResolver().insert(Notes.CONTENT_URI, values); + + if (Intent.ACTION_SEND.equals(action)) { + values.put(Notes.NOTE, + getIntent().getStringExtra(Intent.EXTRA_TEXT)); + mUri = getContentResolver().insert(Notes.CONTENT_URI, + values); } else { - mUri = getContentResolver().insert(intent.getData(), values); + mUri = getContentResolver() + .insert(intent.getData(), values); } // If we were unable to create a new note, then just finish - // this activity. A RESULT_CANCELED will be sent back to the + // this activity. A RESULT_CANCELED will be sent back to the // original activity if they requested a result. if (mUri == null) { - Log.e(TAG, "Failed to insert new note into " + getIntent().getData()); + Log.e(TAG, "Failed to insert new note into " + + getIntent().getData()); finish(); return; } // The new entry was created, so assume all will end well and // set the result to be returned. - //setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); + // setResult(RESULT_OK, (new + // Intent()).setAction(mUri.toString())); setResult(RESULT_OK, intent); } else { - // Whoops, unknown action! Bail. + // Whoops, unknown action! Bail. Log.e(TAG, "Unknown action, exiting"); finish(); return; } } - - //setup actionbar - if(mActionBarAvailable){ + + // setup actionbar + if (mActionBarAvailable) { requestWindowFeature(Window.FEATURE_ACTION_BAR); WrapActionBar bar = new WrapActionBar(this); bar.setDisplayHomeAsUpEnabled(true); - //force to show the actionbar on version 14+ - if(Integer.valueOf(android.os.Build.VERSION.SDK) >= 14){ + // force to show the actionbar on version 14+ + if (Integer.valueOf(android.os.Build.VERSION.SDK) >= 14) { bar.setHomeButtonEnabled(true); } - }else{ + } else { requestWindowFeature(Window.FEATURE_RIGHT_ICON); } - - // Set the layout for this activity. You can find it in res/layout/note_editor.xml + + // Set the layout for this activity. You can find it in + // res/layout/note_editor.xml setContentView(R.layout.note_editor); // The text view for our note, identified by its ID in the XML file. @@ -523,23 +530,25 @@ protected void onCreate(Bundle savedInstanceState) { if (mState != STATE_EDIT_NOTE_FROM_SDCARD) { // Check if we load a note from notepad or from some external module - if(mState == STATE_EDIT_EXTERNAL_NOTE){ - // Get all the columns as we don't know which columns are supported. + if (mState == STATE_EDIT_EXTERNAL_NOTE) { + // Get all the columns as we don't know which columns are + // supported. mCursor = managedQuery(mUri, null, null, null, null); - - //Now check which columns are available - List<String> columnNames = Arrays.asList(mCursor.getColumnNames()); - - if(!columnNames.contains(Notes.NOTE)){ + + // Now check which columns are available + List<String> columnNames = Arrays.asList(mCursor + .getColumnNames()); + + if (!columnNames.contains(Notes.NOTE)) { hasNoteColumn = false; } - if(!columnNames.contains(Notes.TAGS)){ + if (!columnNames.contains(Notes.TAGS)) { hasTagsColumn = false; } - if(!columnNames.contains(Notes.ENCRYPTED)){ + if (!columnNames.contains(Notes.ENCRYPTED)) { hasEncryptionColumn = false; } - if(!columnNames.contains(Notes.THEME)){ + if (!columnNames.contains(Notes.THEME)) { hasThemeColumn = false; } if(!columnNames.contains(Notes.COLOR)){ @@ -548,52 +557,53 @@ protected void onCreate(Bundle savedInstanceState) { if(!columnNames.contains(Notes.SELECTION_START)){ hasSelection_startColumn = false; } - if(!columnNames.contains(Notes.SELECTION_END)){ + if (!columnNames.contains(Notes.SELECTION_END)) { hasSelection_endColumn = false; } - } - else{ + } else { // Get the note! mCursor = managedQuery(mUri, PROJECTION, null, null, null); - - //It's not an external note, so all the columns are available in the database - } + + // It's not an external note, so all the columns are available + // in the database + } } else { mCursor = null; } - - mText.addTextChangedListener(mTextWatcherCharCount); + + mText.addTextChangedListener(mTextWatcherCharCount); } - + /** - * Return intent data when invoked with action=android.intent.action.CREATE_SHORTCUT + * Return intent data when invoked with + * action=android.intent.action.CREATE_SHORTCUT */ private void createShortcut() { - Intent intent = new Intent(Intent.ACTION_INSERT, - Notes.CONTENT_URI, getApplicationContext(), NoteEditor.class); - + Intent intent = new Intent(Intent.ACTION_INSERT, Notes.CONTENT_URI, + getApplicationContext(), NoteEditor.class); + Intent result = new Intent(); result.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); result.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - ShortcutIconResource.fromContext( - getApplicationContext(), + ShortcutIconResource.fromContext(getApplicationContext(), R.drawable.ic_launcher_notepad)); - result.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.new_note)); - + result.putExtra(Intent.EXTRA_SHORTCUT_NAME, + getString(R.string.new_note)); + setResult(RESULT_OK, result); - + finish(); } /** * Returns most recently used theme, or null. + * * @return */ private String getMostRecentlyUsedTheme() { String theme = null; - Cursor c = getContentResolver().query( - Notes.CONTENT_URI, - new String[] {Notes.THEME}, null, null, + Cursor c = getContentResolver().query(Notes.CONTENT_URI, + new String[] { Notes.THEME }, null, null, Notes.MODIFIED_DATE + " DESC"); if (c != null && c.moveToFirst()) { theme = c.getString(0); @@ -604,27 +614,28 @@ private String getMostRecentlyUsedTheme() { private TextWatcher mTextWatcherSdCard = new TextWatcher() { public void afterTextChanged(Editable s) { - //if (debug) Log.d(TAG, "after"); + // if (debug) Log.d(TAG, "after"); mFileContent = s.toString(); updateTitleSdCard(); } public void beforeTextChanged(CharSequence s, int start, int count, int after) { - //if (debug) Log.d(TAG, "before"); + // if (debug) Log.d(TAG, "before"); } public void onTextChanged(CharSequence s, int start, int before, int count) { - //if (debug) Log.d(TAG, "on"); + // if (debug) Log.d(TAG, "on"); } }; - + private TextWatcher mTextWatcherCharCount = new TextWatcher() { - public void afterTextChanged(Editable s){ + public void afterTextChanged(Editable s) { updateCharCount(); } + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @@ -666,8 +677,8 @@ public String readFile(File file) { } catch (FileNotFoundException e) { Log.e(TAG, "File not found", e); - Toast.makeText(this, R.string.file_not_found, - Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.file_not_found, Toast.LENGTH_SHORT) + .show(); return null; } catch (IOException e) { Log.e(TAG, "File not found", e); @@ -682,9 +693,11 @@ public String readFile(File file) { @Override protected void onResume() { super.onResume(); - if (debug) Log.d(TAG, "onResume"); + if (debug) + Log.d(TAG, "onResume"); - if (debug) Log.d(TAG, "mDecrypted: " + mDecryptedText); + if (debug) + Log.d(TAG, "mDecrypted: " + mDecryptedText); // Set auto-link on or off, based on the current setting. int autoLink = PreferenceActivity.getAutoLinkFromPreference(this); @@ -705,10 +718,12 @@ protected void onResume() { } // Make sure that we don't use the link movement method. - // Instead, we need a blend between the arrow key movement (for regular navigation) and + // Instead, we need a blend between the arrow key movement (for regular + // navigation) and // the link movement (so the user can click on links). mText.setMovementMethod(new ArrowKeyMovementMethod() { - public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { + public boolean onTouchEvent(TextView widget, Spannable buffer, + MotionEvent event) { // This block is copied and pasted from LinkMovementMethod's // onTouchEvent (without the part that actually changes the // selection). @@ -728,7 +743,8 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + ClickableSpan[] link = buffer.getSpans(off, off, + ClickableSpan.class); if (link.length != 0) { link[0].onClick(widget); @@ -737,10 +753,8 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event } return super.onTouchEvent(widget, buffer, event); - } - } - ); - + } + }); setTheme(loadTheme()); } @@ -748,9 +762,7 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event private void getNoteFromContentProvider() { // If we didn't have any trouble retrieving the data, it is now // time to get at the stuff. - if (mCursor != null - && mCursor.requery() - && mCursor.moveToFirst()) { + if (mCursor != null && mCursor.requery() && mCursor.moveToFirst()) { // Modify our overall title depending on the mode we are running in. if (mState == STATE_EDIT || mState == STATE_EDIT_EXTERNAL_NOTE) { @@ -758,56 +770,49 @@ private void getNoteFromContentProvider() { } else if (mState == STATE_INSERT) { setTitle(getText(R.string.title_create)); } - + // This always has to be available long id = mCursor.getLong(mCursor.getColumnIndex(Notes._ID)); - String note = ""; - - if(mState == STATE_EDIT_EXTERNAL_NOTE){ - //Check if the other columns are available - + String note = ""; + + if (mState == STATE_EDIT_EXTERNAL_NOTE) { + // Check if the other columns are available + // Note - if(hasNoteColumn){ - note = mCursor.getString(mCursor.getColumnIndex(Notes.NOTE)); - } - else{ + if (hasNoteColumn) { + note = mCursor + .getString(mCursor.getColumnIndex(Notes.NOTE)); + } else { note = ""; } - + // Encrypted mEncrypted = isNoteUnencrypted() ? 0 : 1; - - // Color - if(hasColorColumn){ - mColor = mCursor.getInt(mCursor.getColumnIndex(Notes.COLOR)); - setNoteColor(mColor); - } // Theme - if(hasThemeColumn){ - mTheme = mCursor.getString(mCursor.getColumnIndex(Notes.THEME)); - } - else{ - //note = ""; + if (hasThemeColumn) { + mTheme = mCursor.getString(mCursor + .getColumnIndex(Notes.THEME)); + } else { + note = ""; } - + // Selection start - if(hasSelection_startColumn){ - mSelectionStart = mCursor.getInt(mCursor.getColumnIndex(Notes.SELECTION_START)); - } - else{ + if (hasSelection_startColumn) { + mSelectionStart = mCursor.getInt(mCursor + .getColumnIndex(Notes.SELECTION_START)); + } else { mSelectionStart = 0; } - - //Selection end - if(hasSelection_endColumn){ - mSelectionStop = mCursor.getInt(mCursor.getColumnIndex(Notes.SELECTION_END)); - } - else{ + + // Selection end + if (hasSelection_endColumn) { + mSelectionStop = mCursor.getInt(mCursor + .getColumnIndex(Notes.SELECTION_END)); + } else { mSelectionStop = 0; } - } - else{ + } else { // We know for sure all the columns are available note = mCursor.getString(COLUMN_INDEX_NOTE); mEncrypted = mCursor.getLong(COLUMN_INDEX_ENCRYPTED); @@ -820,10 +825,12 @@ private void getNoteFromContentProvider() { if (mEncrypted == 0) { // Not encrypted - // This is a little tricky: we may be resumed after previously being - // paused/stopped. We want to put the new text in the text view, - // but leave the user where they were (retain the cursor position - // etc). This version of setText does that for us. + // This is a little tricky: we may be resumed after previously + // being + // paused/stopped. We want to put the new text in the text view, + // but leave the user where they were (retain the cursor + // position + // etc). This version of setText does that for us. if (!note.equals(mText.getText().toString())) { mText.setTextKeepState(note); // keep state does not work, so we have to do it manually: @@ -832,21 +839,25 @@ private void getNoteFromContentProvider() { } else { if (mDecryptedText != null) { // Text had already been decrypted, use that: - if (debug) Log.d(TAG, "set decrypted text as mText: " + mDecryptedText); + if (debug) + Log.d(TAG, "set decrypted text as mText: " + + mDecryptedText); mText.setTextKeepState(mDecryptedText); // keep state does not work, so we have to do it manually: mText.setSelection(mSelectionStart, mSelectionStop); if (!mActionBarAvailable) { - setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, android.R.drawable.ic_lock_idle_lock); + setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, + android.R.drawable.ic_lock_idle_lock); } } else { // Decrypt note - if (debug) Log.d(TAG, "Decrypt note: " + note); + if (debug) + Log.d(TAG, "Decrypt note: " + note); // Overwrite mText because it may contain unencrypted note // from savedInstanceState. - //mText.setText(R.string.encrypted); + // mText.setText(R.string.encrypted); Intent i = new Intent(); i.setAction(CryptoIntents.ACTION_DECRYPT); @@ -856,8 +867,7 @@ private void getNoteFromContentProvider() { try { startActivityForResult(i, REQUEST_CODE_DECRYPT); } catch (ActivityNotFoundException e) { - Toast.makeText(this, - R.string.decryption_failed, + Toast.makeText(this, R.string.decryption_failed, Toast.LENGTH_SHORT).show(); Log.e(TAG, "failed to invoke decrypt"); } @@ -865,7 +875,7 @@ private void getNoteFromContentProvider() { } // If we hadn't previously retrieved the original text, do so - // now. This allows the user to revert their changes. + // now. This allows the user to revert their changes. if (mOriginalContent == null) { mOriginalContent = note; } @@ -877,7 +887,8 @@ private void getNoteFromContentProvider() { } private void getNoteFromFile() { - if (debug) Log.d(TAG, "file: " + mFileContent); + if (debug) + Log.d(TAG, "file: " + mFileContent); mText.setTextKeepState(mFileContent); // keep state does not work, so we have to do it manually: @@ -888,7 +899,7 @@ private void getNoteFromFile() { } // If we hadn't previously retrieved the original text, do so - // now. This allows the user to revert their changes. + // now. This allows the user to revert their changes. if (mOriginalContent == null) { mOriginalContent = mFileContent; } @@ -903,11 +914,12 @@ private void updateTitleSdCard() { } String filename = FileUriUtils.getFilename(mUri); setTitle(modified + filename); - //setTitle(getString(R.string.title_edit_file, modified + filename)); - //setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, android.R.drawable.ic_menu_save); + // setTitle(getString(R.string.title_edit_file, modified + filename)); + // setFeatureDrawableResource(Window.FEATURE_RIGHT_ICON, + // android.R.drawable.ic_menu_save); } - private void updateCharCount(){ + private void updateCharCount() { boolean charCountVisible = false; String currentTitle = getTitle().toString(); if (currentTitle.startsWith("[")) { @@ -915,7 +927,8 @@ private void updateCharCount(){ } if (PreferenceActivity.getCharCountEnabledFromPrefs(this)) { if (charCountVisible) { - setTitle("[" + mText.length() + "]" + currentTitle.substring(currentTitle.indexOf(" "))); + setTitle("[" + mText.length() + "]" + + currentTitle.substring(currentTitle.indexOf(" "))); } else { setTitle("[" + mText.length() + "] " + currentTitle); } @@ -928,8 +941,9 @@ private void updateCharCount(){ @Override protected void onSaveInstanceState(Bundle outState) { - if (debug) Log.d(TAG, "onSaveInstanceState"); - //if (debug) Log.d(TAG, "file content: " + mFileContent); + if (debug) + Log.d(TAG, "onSaveInstanceState"); + // if (debug) Log.d(TAG, "file content: " + mFileContent); // Save away the original text, so we still have it if the activity // needs to be killed while paused. @@ -937,7 +951,9 @@ protected void onSaveInstanceState(Bundle outState) { mSelectionStop = mText.getSelectionEnd(); mFileContent = mText.getText().toString(); - if (debug) Log.d(TAG, "Selection " + mSelectionStart + " - " + mSelectionStop + " for text : " + mFileContent); + if (debug) + Log.d(TAG, "Selection " + mSelectionStart + " - " + mSelectionStop + + " for text : " + mFileContent); outState.putString(BUNDLE_ORIGINAL_CONTENT, mOriginalContent); outState.putString(BUNDLE_UNDO_REVERT, mUndoRevert); @@ -954,24 +970,25 @@ protected void onSaveInstanceState(Bundle outState) { @Override protected void onPause() { super.onPause(); - if (debug) Log.d(TAG, "onPause"); + if (debug) + Log.d(TAG, "onPause"); mText.setAutoLinkMask(0); // The user is going somewhere else, so make sure their current - // changes are safely saved away in the provider. We don't need + // changes are safely saved away in the provider. We don't need // to do this if only editing. if (mCursor != null) { mCursor.moveToFirst(); - + if (isNoteUnencrypted()) { String text = mText.getText().toString(); int length = text.length(); // If this activity is finished, and there is no text, then we // do something a little special: simply delete the note entry. - // Note that we do this both for editing and inserting... it + // Note that we do this both for editing and inserting... it // would be reasonable to only do it when inserting. if (isFinishing() && (length == 0) && !mNoteOnly) { setResult(RESULT_CANCELED); @@ -981,20 +998,23 @@ protected void onPause() { } else { ContentValues values = new ContentValues(); - // This stuff is only done when working with a full-fledged note. + // This stuff is only done when working with a full-fledged + // note. if (!mNoteOnly) { String oldText = ""; - Cursor cursor = getContentResolver().query(mUri, new String[]{"note"}, null, null, null); - if ( cursor.moveToFirst() ) { + Cursor cursor = getContentResolver().query(mUri, + new String[] { "note" }, null, null, null); + if (cursor.moveToFirst()) { oldText = cursor.getString(0); } - if ( ! oldText.equals(text) ) { + if (!oldText.equals(text)) { // Bump the modification time to now. - values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); + values.put(Notes.MODIFIED_DATE, + System.currentTimeMillis()); } String title; - if(PreferenceActivity.getMarqueeFromPrefs(this) == false) { + if (PreferenceActivity.getMarqueeFromPrefs(this) == false) { title = ExtractTitle.extractTitle(text); } else { title = text; @@ -1003,10 +1023,10 @@ protected void onPause() { } // Write our text back into the provider. - if(hasNoteColumn){ + if (hasNoteColumn) { values.put(Notes.NOTE, text); } - if(hasThemeColumn){ + if (hasThemeColumn) { values.put(Notes.THEME, mTheme); } if(hasColorColumn){ @@ -1017,11 +1037,13 @@ protected void onPause() { } if(hasSelection_endColumn){ values.put(Notes.SELECTION_END, mText.getSelectionEnd()); - } + } - // Commit all of our changes to persistent storage. When the update completes - // the content provider will notify the cursor of the change, which will - // cause the UI to be updated. + // Commit all of our changes to persistent storage. When the + // update completes + // the content provider will notify the cursor of the + // change, which will + // cause the UI to be updated. getContentResolver().update(mUri, values, null, null); } } else { @@ -1029,14 +1051,14 @@ protected void onPause() { // Save current theme: ContentValues values = new ContentValues(); - - if(hasThemeColumn){ + + if (hasThemeColumn) { values.put(Notes.THEME, mTheme); } if(hasColorColumn){ values.put(Notes.COLOR, mColor); } - + getContentResolver().update(mUri, values, null, null); if (mDecryptedText != null) { @@ -1046,7 +1068,7 @@ protected void onPause() { encryptNote(false); // Remove displayed note. - //mText.setText(R.string.encrypted); + // mText.setText(R.string.encrypted); } } } @@ -1054,18 +1076,19 @@ protected void onPause() { /** * Encrypt the current note. + * * @param text */ private void encryptNote(boolean encryptTags) { String text = mText.getText().toString(); String title; - if(PreferenceActivity.getMarqueeFromPrefs(this) == false) { + if (PreferenceActivity.getMarqueeFromPrefs(this) == false) { title = ExtractTitle.extractTitle(text); } else { title = text; } String tags = getTags(); - //Log.i(TAG, "encrypt tags: " + tags); + // Log.i(TAG, "encrypt tags: " + tags); boolean isNoteEncrypted = !isNoteUnencrypted(); @@ -1073,12 +1096,15 @@ private void encryptNote(boolean encryptTags) { tags = null; } - if (debug) Log.d(TAG, "encrypt note: " + text); + if (debug) + Log.d(TAG, "encrypt note: " + text); if (EncryptActivity.getPendingEncryptActivities() == 0) { Intent i = new Intent(this, EncryptActivity.class); - i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, CryptoIntents.ACTION_ENCRYPT); - i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, EncryptActivity.getCryptoStringArray(text, title, tags)); + i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, + CryptoIntents.ACTION_ENCRYPT); + i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, + EncryptActivity.getCryptoStringArray(text, title, tags)); i.putExtra(PrivateNotePadIntents.EXTRA_URI, mUri.toString()); if (text.equals(mOriginalContent) && isNoteEncrypted) { // No need to encrypt, content was not modified. @@ -1087,9 +1113,11 @@ private void encryptNote(boolean encryptTags) { startActivity(i); // Remove knowledge of the decrypted note. - // If encryption fails because one has been locked out, (another) user + // If encryption fails because one has been locked out, (another) + // user // should not be able to see note again from cache. - if (debug) Log.d(TAG, "using static decrypted text: " + text); + if (debug) + Log.d(TAG, "using static decrypted text: " + text); sDecryptedText = text; if (isNoteEncrypted) { // Already encrypted @@ -1103,26 +1131,29 @@ private void encryptNote(boolean encryptTags) { EncryptActivity.confirmEncryptActivityCalled(); } else { // encrypt already called - if (debug) Log.d(TAG, "encrypt already called"); + if (debug) + Log.d(TAG, "encrypt already called"); } } public static void deleteStaticDecryptedText() { - if (debug) Log.d(TAG, "deleting decrypted text: " + sDecryptedText); + if (debug) + Log.d(TAG, "deleting decrypted text: " + sDecryptedText); sDecryptedText = null; } /** * Unencrypt the current note. + * * @param text */ private void unencryptNote() { String text = mText.getText().toString(); String title = ExtractTitle.extractTitle(text); String tags = getTags(); - //Log.i(TAG, "unencrypt tags: " + tags); + // Log.i(TAG, "unencrypt tags: " + tags); ContentValues values = new ContentValues(); values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); @@ -1137,22 +1168,25 @@ private void unencryptNote() { setFeatureDrawable(Window.FEATURE_RIGHT_ICON, null); } - // Small trick: Tags have not been converted properly yet. Let's do it now: + // Small trick: Tags have not been converted properly yet. Let's do it + // now: Intent i = new Intent(this, EncryptActivity.class); - i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, CryptoIntents.ACTION_DECRYPT); - i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, EncryptActivity.getCryptoStringArray(null, null, tags)); + i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, + CryptoIntents.ACTION_DECRYPT); + i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, + EncryptActivity.getCryptoStringArray(null, null, tags)); i.putExtra(PrivateNotePadIntents.EXTRA_URI, mUri.toString()); startActivity(i); } private String getTags() { String tags; - - //Check if there is a tags column in the database + + // Check if there is a tags column in the database int index; - if((index = mCursor.getColumnIndex(Notes.TAGS)) != -1){ - tags = mCursor.getString(index); } - else{ + if ((index = mCursor.getColumnIndex(Notes.TAGS)) != -1) { + tags = mCursor.getString(index); + } else { tags = ""; } @@ -1169,79 +1203,73 @@ public boolean onCreateOptionsMenu(Menu menu) { // Build the menus that are shown when editing. - //if (!mOriginalContent.equals(mText.getText().toString())) { + // if (!mOriginalContent.equals(mText.getText().toString())) { - menu.add(0, MENU_REVERT, 0, R.string.menu_revert) - .setShortcut('0', 'r') - .setIcon(android.R.drawable.ic_menu_revert); - //} + menu.add(0, MENU_REVERT, 0, R.string.menu_revert).setShortcut('0', 'r') + .setIcon(android.R.drawable.ic_menu_revert); + // } menu.add(1, MENU_ENCRYPT, 0, R.string.menu_encrypt) - .setShortcut('1', 'e') - .setIcon(android.R.drawable.ic_lock_lock); // TODO: better icon + .setShortcut('1', 'e').setIcon(android.R.drawable.ic_lock_lock); // TODO: + // better + // icon menu.add(1, MENU_UNENCRYPT, 0, R.string.menu_undo_encryption) - .setShortcut('1', 'e') - .setIcon(android.R.drawable.ic_lock_lock); // TODO: better icon + .setShortcut('1', 'e').setIcon(android.R.drawable.ic_lock_lock); // TODO: + // better + // icon MenuItem item = menu.add(1, MENU_DELETE, 0, R.string.menu_delete); item.setIcon(android.R.drawable.ic_menu_delete); - - menu.add(2, MENU_IMPORT, 0, R.string.menu_import) - .setShortcut('1', 'i') - .setIcon(android.R.drawable.ic_menu_add); - menu.add(2, MENU_SAVE, 0, R.string.menu_save) - .setShortcut('2', 's') - .setIcon(android.R.drawable.ic_menu_save); + menu.add(2, MENU_IMPORT, 0, R.string.menu_import).setShortcut('1', 'i') + .setIcon(android.R.drawable.ic_menu_add); + + menu.add(2, MENU_SAVE, 0, R.string.menu_save).setShortcut('2', 's') + .setIcon(android.R.drawable.ic_menu_save); menu.add(2, MENU_SAVE_AS, 0, R.string.menu_save_as) - .setShortcut('3', 'w') - .setIcon(android.R.drawable.ic_menu_save); + .setShortcut('3', 'w').setIcon(android.R.drawable.ic_menu_save); - menu.add(3, MENU_THEME, 0, R.string.menu_theme).setIcon( - android.R.drawable.ic_menu_manage).setShortcut('4', 't'); + menu.add(3, MENU_THEME, 0, R.string.menu_theme) + .setIcon(android.R.drawable.ic_menu_manage) + .setShortcut('4', 't'); - menu.add(3, MENU_SETTINGS, 0, R.string.settings).setIcon( - android.R.drawable.ic_menu_preferences).setShortcut('9', 'p'); + menu.add(3, MENU_SETTINGS, 0, R.string.settings) + .setIcon(android.R.drawable.ic_menu_preferences) + .setShortcut('9', 'p'); - item = menu.add(4, MENU_COLOR, 0, R.string.menu_color); - item.setIcon( R.drawable.notes_btn_changecolors ); - if(mActionBarAvailable){ + item = menu.add(4, MENU_SEND, 0, R.string.menu_share); + item.setIcon(android.R.drawable.ic_menu_share); + if (mActionBarAvailable) { WrapActionBar.showIfRoom(item); } - item = menu.add(5, MENU_SEND, 0, R.string.menu_share); - item.setIcon(android.R.drawable.ic_menu_share); + + item = menu.add(4, MENU_COLOR, 0, R.string.menu_color); + item.setIcon( R.drawable.notes_btn_changecolors ); if(mActionBarAvailable){ WrapActionBar.showIfRoom(item); } - + menu.add(5, MENU_WORD_COUNT, 0, R.string.menu_word_count); - + /* - if (mState == STATE_EDIT) { - - menu.add(0, REVERT_ID, 0, R.string.menu_revert) - .setShortcut('0', 'r') - .setIcon(android.R.drawable.ic_menu_revert); - - if (!mNoteOnly) { - menu.add(1, DELETE_ID, 0, R.string.menu_delete) - .setShortcut('1', 'd') - .setIcon(android.R.drawable.ic_menu_delete); - } - - // Build the menus that are shown when inserting. - } else { - menu.add(1, DISCARD_ID, 0, R.string.menu_discard) - .setShortcut('0', 'd') - .setIcon(android.R.drawable.ic_menu_delete); - } + * if (mState == STATE_EDIT) { + * + * menu.add(0, REVERT_ID, 0, R.string.menu_revert) .setShortcut('0', + * 'r') .setIcon(android.R.drawable.ic_menu_revert); + * + * if (!mNoteOnly) { menu.add(1, DELETE_ID, 0, R.string.menu_delete) + * .setShortcut('1', 'd') .setIcon(android.R.drawable.ic_menu_delete); } + * + * // Build the menus that are shown when inserting. } else { + * menu.add(1, DISCARD_ID, 0, R.string.menu_discard) .setShortcut('0', + * 'd') .setIcon(android.R.drawable.ic_menu_delete); } */ // If we are working on a full note, then append to the // menu items for any other activities that can do stuff with it - // as well. This does a query on the system for any activities that + // as well. This does a query on the system for any activities that // implement the ALTERNATIVE_ACTION for our data, adding a menu item // for each one that is found. if (!mNoteOnly) { @@ -1250,13 +1278,16 @@ public boolean onCreateOptionsMenu(Menu menu) { // a new note. Intent intent = new Intent(null, mUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); - //menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, - // new ComponentName(this, NoteEditor.class), null, intent, 0, null); + // menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, + // new ComponentName(this, NoteEditor.class), null, intent, 0, + // null); // Workaround to add icons: - MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, menu); + MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons( + this, menu); menu2.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, - new ComponentName(this, NoteEditor.class), null, intent, 0, null); + new ComponentName(this, NoteEditor.class), null, intent, 0, + null); // Add menu items for category CATEGORY_TEXT_SELECTION_ALTERNATIVE intent = new Intent(); // Don't pass data for this intent @@ -1264,7 +1295,8 @@ public boolean onCreateOptionsMenu(Menu menu) { intent.setType("text/plain"); // Workaround to add icons: menu2.addIntentOptions(GROUP_ID_TEXT_SELECTION_ALTERNATIVE, 0, 0, - new ComponentName(this, NoteEditor.class), null, intent, 0, null); + new ComponentName(this, NoteEditor.class), null, intent, 0, + null); } @@ -1275,11 +1307,11 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) { // Show "revert" menu item only if content has changed. - boolean contentChanged = !mOriginalContent.equals(mText.getText().toString()); + boolean contentChanged = !mOriginalContent.equals(mText.getText() + .toString()); boolean isNoteUnencrypted = isNoteUnencrypted(); - // Show comands on the URI only if the note is not encrypted menu.setGroupVisible(Menu.CATEGORY_ALTERNATIVE, isNoteUnencrypted); @@ -1314,11 +1346,11 @@ public boolean onPrepareOptionsMenu(Menu menu) { private boolean isNoteUnencrypted() { long encrypted = 0; if (mCursor != null && mCursor.moveToFirst()) { - //Check if the column Notes.ENCRYPTED exists - if(hasEncryptionColumn){ - encrypted = mCursor.getInt(mCursor.getColumnIndex(Notes.ENCRYPTED)); - } - else{ + // Check if the column Notes.ENCRYPTED exists + if (hasEncryptionColumn) { + encrypted = mCursor.getInt(mCursor + .getColumnIndex(Notes.ENCRYPTED)); + } else { encrypted = 0; } } @@ -1330,50 +1362,50 @@ private boolean isNoteUnencrypted() { public boolean onOptionsItemSelected(MenuItem item) { // Handle all of the possible menu actions. switch (item.getItemId()) { - case android.R.id.home: - Intent intent = new Intent(this, NotesList.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - break; - case MENU_DELETE: - deleteNoteWithConfirm(); - break; - case MENU_DISCARD: - revertNote(); - break; - case MENU_REVERT: - revertNote(); - break; - case MENU_ENCRYPT: - encryptNote(true); - break; - case MENU_UNENCRYPT: - unencryptNote(); - break; - case MENU_IMPORT: - importNote(); - break; - case MENU_SAVE: - saveNote(); - break; - case MENU_SAVE_AS: - saveAsNote(); - break; - case MENU_THEME: - setThemeSettings(); - return true; - case MENU_SETTINGS: - showNotesListSettings(); - return true; - case MENU_SEND: - shareNote(); - return true; - case MENU_COLOR: - setColor(); - return true; - case MENU_WORD_COUNT: - showWordCount(); - break; + case android.R.id.home: + Intent intent = new Intent(this, NotesList.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + break; + case MENU_DELETE: + deleteNoteWithConfirm(); + break; + case MENU_DISCARD: + revertNote(); + break; + case MENU_REVERT: + revertNote(); + break; + case MENU_ENCRYPT: + encryptNote(true); + break; + case MENU_UNENCRYPT: + unencryptNote(); + break; + case MENU_IMPORT: + importNote(); + break; + case MENU_SAVE: + saveNote(); + break; + case MENU_SAVE_AS: + saveAsNote(); + break; + case MENU_THEME: + setThemeSettings(); + return true; + case MENU_SETTINGS: + showNotesListSettings(); + return true; + case MENU_SEND: + shareNote(); + return true; + case MENU_COLOR: + setColor(); + return true; + case MENU_WORD_COUNT: + showWordCount(); + break; } if (item.getGroupId() == GROUP_ID_TEXT_SELECTION_ALTERNATIVE) { // Process manually: @@ -1388,47 +1420,47 @@ public boolean onOptionsItemSelected(MenuItem item) { private void setColor() { LinearLayout color = (LinearLayout) findViewById(R.id.editor_color); - ImageView color_yellow = (ImageView) findViewById(R.id.editor_color_yellow); - ImageView color_pink = (ImageView) findViewById(R.id.editor_color_pink); - ImageView color_blue = (ImageView) findViewById(R.id.editor_color_blue); - ImageView color_green = (ImageView) findViewById(R.id.editor_color_green); - ImageView color_gray = (ImageView) findViewById(R.id.editor_color_gray); - - color_yellow.setOnClickListener(colorListener); - color_pink.setOnClickListener(colorListener); - color_blue.setOnClickListener(colorListener); - color_green.setOnClickListener(colorListener); - color_gray.setOnClickListener(colorListener); - - color.setVisibility(View.VISIBLE); + ImageView color_yellow = (ImageView) findViewById(R.id.editor_color_yellow); + ImageView color_pink = (ImageView) findViewById(R.id.editor_color_pink); + ImageView color_blue = (ImageView) findViewById(R.id.editor_color_blue); + ImageView color_green = (ImageView) findViewById(R.id.editor_color_green); + ImageView color_gray = (ImageView) findViewById(R.id.editor_color_gray); + + color_yellow.setOnClickListener(colorListener); + color_pink.setOnClickListener(colorListener); + color_blue.setOnClickListener(colorListener); + color_green.setOnClickListener(colorListener); + color_gray.setOnClickListener(colorListener); + + color.setVisibility(View.VISIBLE); } - OnClickListener colorListener = new OnClickListener() { - @Override - public void onClick(View v) { - // TODO Auto-generated method stub - switch (v.getId()) { - case R.id.editor_color_yellow: - setNoteColor(YELLOW); - break; - case R.id.editor_color_pink: - setNoteColor(PINK); - break; - case R.id.editor_color_blue: - setNoteColor(BLUE); - break; - case R.id.editor_color_green: - setNoteColor(GREEN); - break; - case R.id.editor_color_gray: - setNoteColor(GREY); - break; - default: - break; - } - } - }; - + OnClickListener colorListener = new OnClickListener() { + @Override + public void onClick(View v) { + // TODO Auto-generated method stub + switch (v.getId()) { + case R.id.editor_color_yellow: + setNoteColor(YELLOW); + break; + case R.id.editor_color_pink: + setNoteColor(PINK); + break; + case R.id.editor_color_blue: + setNoteColor(BLUE); + break; + case R.id.editor_color_green: + setNoteColor(GREEN); + break; + case R.id.editor_color_gray: + setNoteColor(GREY); + break; + default: + break; + } + } + }; + private void shareNote() { String content = mText.getText().toString(); String title = ExtractTitle.extractTitle(content); @@ -1439,8 +1471,8 @@ protected void setNoteColor(int color) { int id = (int)R.color.lightYellow; Resources res = getResources(); LinearLayout c = (LinearLayout) findViewById(R.id.editor_color); - c.setVisibility(View.GONE); - + c.setVisibility(View.GONE); + switch (color) { case BLUE: id = (int)R.color.lightBabyBlue; @@ -1458,8 +1490,8 @@ protected void setNoteColor(int color) { break; } - mText.setBackgroundDrawable(res.getDrawable(id)); - + mText.setBackgroundDrawable(res.getDrawable(id)); + if (color == mColor) return; mColor = color; @@ -1474,6 +1506,7 @@ private void deleteNoteWithConfirm() { /** * Modifies an activity to pass along the currently selected text. + * * @param intent */ private void startTextSelectionActivity(Intent intent) { @@ -1483,18 +1516,23 @@ private void startTextSelectionActivity(Intent intent) { int start = mText.getSelectionStart(); int end = mText.getSelectionEnd(); - //if (debug) Log.i(TAG, "len: " + text.length() + ", start: " + start + ", end: " + end); + // if (debug) Log.i(TAG, "len: " + text.length() + ", start: " + start + + // ", end: " + end); if (end < start) { int swap = end; end = start; start = swap; } - newIntent.putExtra(NotepadIntents.EXTRA_TEXT, text.substring(start, end)); - newIntent.putExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION, text.substring(0, start)); - newIntent.putExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION, text.substring(end)); + newIntent.putExtra(NotepadIntents.EXTRA_TEXT, + text.substring(start, end)); + newIntent.putExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION, + text.substring(0, start)); + newIntent.putExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION, + text.substring(end)); - startActivityForResult(newIntent, REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE); + startActivityForResult(newIntent, + REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE); } /** @@ -1504,7 +1542,7 @@ private final void revertNote() { if (mCursor != null) { String tmp = mText.getText().toString(); mText.setAutoLinkMask(0); - if (! tmp.equals(mOriginalContent)) { + if (!tmp.equals(mOriginalContent)) { // revert to original content mText.setTextKeepState(mOriginalContent); mUndoRevert = tmp; @@ -1516,13 +1554,13 @@ private final void revertNote() { int autolink = PreferenceActivity.getAutoLinkFromPreference(this); mText.setAutoLinkMask(autolink); } - //mCursor.requery(); - //setResult(RESULT_CANCELED); - //finish(); + // mCursor.requery(); + // setResult(RESULT_CANCELED); + // finish(); } /** - * Take care of deleting a note. Simply deletes the entry. + * Take care of deleting a note. Simply deletes the entry. */ private final void deleteNote() { if (mCursor != null) { @@ -1532,22 +1570,19 @@ private final void deleteNote() { mText.setText(""); } } + /* - private final void discardNote() { - //if (mCursor != null) { - // mCursor.close(); - // mCursor = null; - // getContentResolver().delete(mUri, null, null); - // mText.setText(""); - //} - mOriginalContent = mText.getText().toString(); - mText.setText(""); - } + * private final void discardNote() { //if (mCursor != null) { // + * mCursor.close(); // mCursor = null; // getContentResolver().delete(mUri, + * null, null); // mText.setText(""); //} mOriginalContent = + * mText.getText().toString(); mText.setText(""); } */ private void applyInsertText() { - if (mApplyTextBefore != null || mApplyText != null || mApplyTextAfter != null) { - // Need to apply insert text from previous TEXT_SELECTION_ALTERNATIVE + if (mApplyTextBefore != null || mApplyText != null + || mApplyTextAfter != null) { + // Need to apply insert text from previous + // TEXT_SELECTION_ALTERNATIVE insertAtPoint(mApplyTextBefore, mApplyText, mApplyTextAfter); @@ -1559,16 +1594,17 @@ private void applyInsertText() { } /** - * Insert textToInsert at current position. - * Optionally, if textBefore or textAfter are non-null, - * replace the text before or after the current selection. + * Insert textToInsert at current position. Optionally, if textBefore or + * textAfter are non-null, replace the text before or after the current + * selection. * * @author isaac * @author Peli */ - private void insertAtPoint (String textBefore, String textToInsert, String textAfter) { + private void insertAtPoint(String textBefore, String textToInsert, + String textAfter) { String originalText = mText.getText().toString(); - int startPos = mText.getSelectionStart(); + int startPos = mText.getSelectionStart(); int endPos = mText.getSelectionEnd(); if (mDecryptedText != null) { // Treat encrypted text: @@ -1578,7 +1614,7 @@ private void insertAtPoint (String textBefore, String textToInsert, String textA } int newStartPos = startPos; int newEndPos = endPos; - ContentValues values = new ContentValues(); + ContentValues values = new ContentValues(); String newNote = ""; StringBuffer sb = new StringBuffer(); if (textBefore != null) { @@ -1609,31 +1645,33 @@ private void insertAtPoint (String textBefore, String textToInsert, String textA } else if (mDecryptedText != null) { mDecryptedText = newNote; } else { - // This stuff is only done when working with a full-fledged note. - if (!mNoteOnly) { - // Bump the modification time to now. - values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); + // This stuff is only done when working with a full-fledged note. + if (!mNoteOnly) { + // Bump the modification time to now. + values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); String title; - if(PreferenceActivity.getMarqueeFromPrefs(this) == false) { + if (PreferenceActivity.getMarqueeFromPrefs(this) == false) { title = ExtractTitle.extractTitle(newNote); } else { title = newNote; } - values.put(Notes.TITLE, title); - } + values.put(Notes.TITLE, title); + } // Write our text back into the provider. values.put(Notes.NOTE, newNote); - // Commit all of our changes to persistent storage. When the update completes - // the content provider will notify the cursor of the change, which will - // cause the UI to be updated. + // Commit all of our changes to persistent storage. When the update + // completes + // the content provider will notify the cursor of the change, which + // will + // cause the UI to be updated. getContentResolver().update(mUri, values, null, null); } - //ijones: notification doesn't seem to trigger for some reason :( + // ijones: notification doesn't seem to trigger for some reason :( mText.setTextKeepState(newNote); // Adjust cursor position according to new length: mText.setSelection(newStartPos, newEndPos); - } + } private void importNote() { // Load the file into a new note. @@ -1643,9 +1681,9 @@ private void importNote() { Uri newUri = null; // Let's check whether the exactly same note already exists or not: - Cursor c = getContentResolver().query(Notes.CONTENT_URI, - new String[] {Notes._ID}, - Notes.NOTE + " = ?", new String[] {mFileContent}, null); + Cursor c = getContentResolver().query(Notes.CONTENT_URI, + new String[] { Notes._ID }, Notes.NOTE + " = ?", + new String[] { mFileContent }, null); if (c != null && c.moveToFirst()) { // Same note exists already: long id = c.getLong(0); @@ -1655,15 +1693,14 @@ private void importNote() { // Add new note // Requested to insert: set that state, and create a new entry // in the container. - //mState = STATE_INSERT; + // mState = STATE_INSERT; ContentValues values = new ContentValues(); values.put(Notes.NOTE, mFileContent); values.put(Notes.THEME, mTheme); newUri = getContentResolver().insert(Notes.CONTENT_URI, values); - // If we were unable to create a new note, then just finish - // this activity. A RESULT_CANCELED will be sent back to the + // this activity. A RESULT_CANCELED will be sent back to the // original activity if they requested a result. if (newUri == null) { Log.e(TAG, "Failed to insert new note."); @@ -1673,11 +1710,10 @@ private void importNote() { // The new entry was created, so assume all will end well and // set the result to be returned. - //setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); - //setResult(RESULT_OK, intent); + // setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); + // setResult(RESULT_OK, intent); } - // Start a new editor: Intent intent = new Intent(); intent.setAction(Intent.ACTION_EDIT); @@ -1722,20 +1758,21 @@ void setThemeSettings() { protected Dialog onCreateDialog(int id) { switch (id) { - case DIALOG_UNSAVED_CHANGES: - return getUnsavedChangesWarningDialog(); + case DIALOG_UNSAVED_CHANGES: + return getUnsavedChangesWarningDialog(); - case DIALOG_THEME: - return new ThemeDialog(this, this); + case DIALOG_THEME: + return new ThemeDialog(this, this); - case DIALOG_DELETE: - return new DeleteConfirmationDialog(this, new DialogInterface.OnClickListener() { + case DIALOG_DELETE: + return new DeleteConfirmationDialog(this, + new DialogInterface.OnClickListener() { - public void onClick(DialogInterface arg0, int arg1) { - deleteNote(); - finish(); - } - }).create(); + public void onClick(DialogInterface arg0, int arg1) { + deleteNote(); + finish(); + } + }).create(); } return null; } @@ -1758,21 +1795,22 @@ public void onSetThemeForAll(String theme) { /** * Set theme for all lists. + * * @param context * @param theme */ public static void setThemeForAll(Context context, String theme) { ContentValues values = new ContentValues(); values.put(Notes.THEME, theme); - context.getContentResolver().update( - Notes.CONTENT_URI, values, null, null); + context.getContentResolver().update(Notes.CONTENT_URI, values, null, + null); } /** * Loads the theme settings for the currently selected theme. * - * Up to version 1.2.1, only one of 3 hardcoded themes are available. These are stored - * in 'skin_background' as '1', '2', or '3'. + * Up to version 1.2.1, only one of 3 hardcoded themes are available. These + * are stored in 'skin_background' as '1', '2', or '3'. * * Starting in 1.2.2, also themes of other packages are allowed. * @@ -1781,30 +1819,23 @@ public static void setThemeForAll(Context context, String theme) { public String loadTheme() { return mTheme; /* - if (mCursor != null && mCursor.moveToFirst()) { - // mCursorListFilter has been set to correct position - // by calling getSelectedListId(), - // so we can read out further elements: - String skinBackground = mCursor - .getString(COLUMN_INDEX_THEME); - - return skinBackground; - } else { - return null; - } + * if (mCursor != null && mCursor.moveToFirst()) { // mCursorListFilter + * has been set to correct position // by calling getSelectedListId(), + * // so we can read out further elements: String skinBackground = + * mCursor .getString(COLUMN_INDEX_THEME); + * + * return skinBackground; } else { return null; } */ } public void saveTheme(String theme) { mTheme = theme; /* - // Save theme only for content Uris with NotePad authority. - // Don't save anything for file:// uri. - if (mUri != null && mUri.getAuthority().equals(NotePad.AUTHORITY)) { - ContentValues values = new ContentValues(); - values.put(Notes.THEME, theme); - getContentResolver().update(mUri, values, null, null); - } + * // Save theme only for content Uris with NotePad authority. // Don't + * save anything for file:// uri. if (mUri != null && + * mUri.getAuthority().equals(NotePad.AUTHORITY)) { ContentValues values + * = new ContentValues(); values.put(Notes.THEME, theme); + * getContentResolver().update(mUri, values, null, null); } */ } @@ -1840,7 +1871,8 @@ private void setLocalStyle(int styleResId, int size) { private boolean setRemoteStyle(String styleName, int size) { if (TextUtils.isEmpty(styleName)) { - if (debug) Log.e(TAG, "Empty style name: " + styleName); + if (debug) + Log.e(TAG, "Empty style name: " + styleName); return false; } @@ -1857,14 +1889,16 @@ private boolean setRemoteStyle(String styleName, int size) { try { c = createPackageContext(packageName, 0); } catch (NameNotFoundException e) { - Log.e(TAG, "Package for style not found: " + packageName + ", " + styleName); + Log.e(TAG, "Package for style not found: " + packageName + ", " + + styleName); return false; } Resources res = c.getResources(); int themeid = res.getIdentifier(styleName, null, null); - if (debug) Log.d(TAG, "Retrieving theme: " + styleName + ", " + themeid); + if (debug) + Log.d(TAG, "Retrieving theme: " + styleName + ", " + themeid); if (themeid == 0) { Log.e(TAG, "Theme name not found: " + styleName); @@ -1875,33 +1909,43 @@ private boolean setRemoteStyle(String styleName, int size) { ThemeAttributes ta = new ThemeAttributes(c, packageName, themeid); mTextTypeface = ta.getString(ThemeNotepad.textTypeface); - if (debug) Log.d(TAG, "textTypeface: " + mTextTypeface); + if (debug) + Log.d(TAG, "textTypeface: " + mTextTypeface); mCurrentTypeface = null; // Look for special cases: if ("monospace".equals(mTextTypeface)) { - mCurrentTypeface = Typeface.create(Typeface.MONOSPACE, Typeface.NORMAL); + mCurrentTypeface = Typeface.create(Typeface.MONOSPACE, + Typeface.NORMAL); } else if ("sans".equals(mTextTypeface)) { - mCurrentTypeface = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); + mCurrentTypeface = Typeface.create(Typeface.SANS_SERIF, + Typeface.NORMAL); } else if ("serif".equals(mTextTypeface)) { - mCurrentTypeface = Typeface.create(Typeface.SERIF, Typeface.NORMAL); + mCurrentTypeface = Typeface.create(Typeface.SERIF, + Typeface.NORMAL); } else if (!TextUtils.isEmpty(mTextTypeface)) { try { - if (debug) Log.d(TAG, "Reading typeface: package: " + packageName + ", typeface: " + mTextTypeface); - Resources remoteRes = pm.getResourcesForApplication(packageName); - mCurrentTypeface = Typeface.createFromAsset(remoteRes.getAssets(), - mTextTypeface); - if (debug) Log.d(TAG, "Result: " + mCurrentTypeface); + if (debug) + Log.d(TAG, "Reading typeface: package: " + packageName + + ", typeface: " + mTextTypeface); + Resources remoteRes = pm + .getResourcesForApplication(packageName); + mCurrentTypeface = Typeface.createFromAsset( + remoteRes.getAssets(), mTextTypeface); + if (debug) + Log.d(TAG, "Result: " + mCurrentTypeface); } catch (NameNotFoundException e) { Log.e(TAG, "Package not found for Typeface", e); } } - mTextUpperCaseFont = ta.getBoolean(ThemeNotepad.textUpperCaseFont, false); + mTextUpperCaseFont = ta.getBoolean(ThemeNotepad.textUpperCaseFont, + false); - mTextColor = ta.getColor(ThemeNotepad.textColor, android.R.color.white); + mTextColor = ta.getColor(ThemeNotepad.textColor, + android.R.color.white); if (debug) { Log.d(TAG, "textColor: " + mTextColor); @@ -1916,25 +1960,35 @@ private boolean setRemoteStyle(String styleName, int size) { } else { mTextSize = getTextSizeLarge(ta); } - if (debug) Log.d(TAG, "textSize: " + mTextSize); + if (debug) + Log.d(TAG, "textSize: " + mTextSize); if (mText != null) { - mBackgroundPadding = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPadding, -1); - int backgroundPaddingLeft = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingLeft, mBackgroundPadding); - int backgroundPaddingTop = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingTop, mBackgroundPadding); - int backgroundPaddingRight = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingRight, mBackgroundPadding); - int backgroundPaddingBottom = ta.getDimensionPixelOffset(ThemeNotepad.backgroundPaddingBottom, mBackgroundPadding); + mBackgroundPadding = ta.getDimensionPixelOffset( + ThemeNotepad.backgroundPadding, -1); + int backgroundPaddingLeft = ta.getDimensionPixelOffset( + ThemeNotepad.backgroundPaddingLeft, mBackgroundPadding); + int backgroundPaddingTop = ta.getDimensionPixelOffset( + ThemeNotepad.backgroundPaddingTop, mBackgroundPadding); + int backgroundPaddingRight = ta + .getDimensionPixelOffset( + ThemeNotepad.backgroundPaddingRight, + mBackgroundPadding); + int backgroundPaddingBottom = ta.getDimensionPixelOffset( + ThemeNotepad.backgroundPaddingBottom, + mBackgroundPadding); if (debug) { - Log.d(TAG, "Padding: " + mBackgroundPadding + "; " + - backgroundPaddingLeft + "; " + - backgroundPaddingTop + "; " + - backgroundPaddingRight + "; " + - backgroundPaddingBottom + "; "); + Log.d(TAG, "Padding: " + mBackgroundPadding + "; " + + backgroundPaddingLeft + "; " + + backgroundPaddingTop + "; " + + backgroundPaddingRight + "; " + + backgroundPaddingBottom + "; "); } try { - Resources remoteRes = pm.getResourcesForApplication(packageName); + Resources remoteRes = pm + .getResourcesForApplication(packageName); int resid = ta.getResourceId(ThemeNotepad.background, 0); if (resid != 0) { Drawable d = remoteRes.getDrawable(resid); @@ -1951,23 +2005,24 @@ private boolean setRemoteStyle(String styleName, int size) { } // Apply padding - if (mBackgroundPadding >=0 - || backgroundPaddingLeft >= 0 || backgroundPaddingTop >= 0 || - backgroundPaddingRight >= 0 || backgroundPaddingBottom >= 0){ - mText.setPadding(backgroundPaddingLeft, - backgroundPaddingTop, - backgroundPaddingRight, + if (mBackgroundPadding >= 0 || backgroundPaddingLeft >= 0 + || backgroundPaddingTop >= 0 + || backgroundPaddingRight >= 0 + || backgroundPaddingBottom >= 0) { + mText.setPadding(backgroundPaddingLeft, + backgroundPaddingTop, backgroundPaddingRight, backgroundPaddingBottom); } else { // 9-patches do the padding automatically - // todo clear padding + // todo clear padding } } mLinesMode = ta.getInteger(ThemeNotepad.lineMode, 2); mLinesColor = ta.getColor(ThemeNotepad.lineColor, 0xFF000080); - if (debug) Log.d(TAG, "line color: " + mLinesColor); + if (debug) + Log.d(TAG, "line color: " + mLinesColor); return true; @@ -1985,38 +2040,35 @@ private boolean setRemoteStyle(String styleName, int size) { } private float getTextSizeTiny(ThemeAttributes ta) { - float size = ta - .getDimensionPixelOffset(ThemeNotepad.textSizeTiny, -1); + float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeTiny, -1); if (size == -1) { // Try to obtain from small: - size = (12f/18f) * getTextSizeSmall(ta); + size = (12f / 18f) * getTextSizeSmall(ta); } return size; } private float getTextSizeSmall(ThemeAttributes ta) { - float size = ta - .getDimensionPixelOffset(ThemeNotepad.textSizeSmall, -1); + float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeSmall, -1); if (size == -1) { // Try to obtain from small: - size = (18f/23f) * getTextSizeMedium(ta); + size = (18f / 23f) * getTextSizeMedium(ta); } return size; } private float getTextSizeMedium(ThemeAttributes ta) { final float scale = getResources().getDisplayMetrics().scaledDensity; - float size = ta - .getDimensionPixelOffset(ThemeNotepad.textSizeMedium, (int) (23 * scale + 0.5f)); + float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeMedium, + (int) (23 * scale + 0.5f)); return size; } private float getTextSizeLarge(ThemeAttributes ta) { - float size = ta - .getDimensionPixelOffset(ThemeNotepad.textSizeLarge, -1); + float size = ta.getDimensionPixelOffset(ThemeNotepad.textSizeLarge, -1); if (size == -1) { // Try to obtain from small: - size = (28f/23f) * getTextSizeMedium(ta); + size = (28f / 23f) * getTextSizeMedium(ta); } return size; } @@ -2027,10 +2079,12 @@ private void applyTheme() { mText.setTextColor(mTextColor); if (mTextUpperCaseFont) { - // Turn off autolinkmask, because it is not compatible with transformationmethod. + // Turn off autolinkmask, because it is not compatible with + // transformationmethod. mText.setAutoLinkMask(0); - mText.setTransformationMethod(UpperCaseTransformationMethod.getInstance()); + mText.setTransformationMethod(UpperCaseTransformationMethod + .getInstance()); } else { mText.setTransformationMethod(null); @@ -2047,7 +2101,7 @@ private void showNotesListSettings() { startActivity(new Intent(this, PreferenceActivity.class)); } - private void showWordCount(){ + private void showWordCount() { String text = mText.getText().toString(); int number_of_words = text.split("\\s+").length; if (TextUtils.isEmpty(text)) { @@ -2055,9 +2109,9 @@ private void showWordCount(){ // so in this case we set it manually number_of_words = 0; } - AlertDialog.Builder wordCountAlert = new AlertDialog.Builder(this); - wordCountAlert.setMessage(getResources().getQuantityString(R.plurals.word_count, - number_of_words, number_of_words)); + AlertDialog.Builder wordCountAlert = new AlertDialog.Builder(this); + wordCountAlert.setMessage(getResources().getQuantityString( + R.plurals.word_count, number_of_words, number_of_words)); wordCountAlert.setTitle(R.string.menu_word_count); wordCountAlert.setPositiveButton(R.string.ok, null); wordCountAlert.setCancelable(false); @@ -2066,34 +2120,33 @@ private void showWordCount(){ Dialog getUnsavedChangesWarningDialog() { return new AlertDialog.Builder(this) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.warning_unsaved_changes_title) - .setMessage(R.string.warning_unsaved_changes_message) - .setPositiveButton(R.string.button_save, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - // Save - saveNote(); - finish(); - } - }) - .setNeutralButton(R.string.button_dont_save, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - // Don't save - finish(); - } - }) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - // Cancel - } - }) - .create(); + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.warning_unsaved_changes_title) + .setMessage(R.string.warning_unsaved_changes_message) + .setPositiveButton(R.string.button_save, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + // Save + saveNote(); + finish(); + } + }) + .setNeutralButton(R.string.button_dont_save, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + // Don't save + finish(); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int whichButton) { + // Cancel + } + }).create(); } @Override @@ -2102,7 +2155,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (mState == STATE_EDIT_NOTE_FROM_SDCARD) { mFileContent = mText.getText().toString(); - if (! mFileContent.equals(mOriginalContent)) { + if (!mFileContent.equals(mOriginalContent)) { // Show a dialog showDialog(DIALOG_UNSAVED_CHANGES); return true; @@ -2113,58 +2166,65 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } - protected void onActivityResult (int requestCode, int resultCode, Intent data) { - if (debug) Log.d(TAG, "onActivityResult: Received requestCode " + requestCode + ", resultCode " + resultCode); - switch(requestCode) { - case REQUEST_CODE_DECRYPT: - if (resultCode == RESULT_OK && data != null) { - String decryptedText = data.getStringExtra (CryptoIntents.EXTRA_TEXT); - long id = data.getLongExtra(PrivateNotePadIntents.EXTRA_ID, -1); - - // TODO: Check that id corresponds to current intent. - - if (id == -1) { - Log.e(TAG, "Wrong extra id"); - Toast.makeText(this, - "Decrypted information incomplete", - Toast.LENGTH_SHORT).show(); - - finish(); - return; - } - - if (debug) Log.d(TAG, "decrypted text received: " + decryptedText); - mDecryptedText = decryptedText; - mOriginalContent = decryptedText; - - } else { - Toast.makeText(this, - R.string.decryption_failed, + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (debug) + Log.d(TAG, "onActivityResult: Received requestCode " + requestCode + + ", resultCode " + resultCode); + switch (requestCode) { + case REQUEST_CODE_DECRYPT: + if (resultCode == RESULT_OK && data != null) { + String decryptedText = data + .getStringExtra(CryptoIntents.EXTRA_TEXT); + long id = data.getLongExtra(PrivateNotePadIntents.EXTRA_ID, -1); + + // TODO: Check that id corresponds to current intent. + + if (id == -1) { + Log.e(TAG, "Wrong extra id"); + Toast.makeText(this, "Decrypted information incomplete", Toast.LENGTH_SHORT).show(); - Log.e(TAG, "decryption failed"); finish(); + return; } - break; - case REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE: - if (resultCode == RESULT_OK && data != null) { - // Insert result at current cursor position: - mApplyText = data.getStringExtra(NotepadIntents.EXTRA_TEXT); - mApplyTextBefore = data.getStringExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION); - mApplyTextAfter = data.getStringExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION); - - // Text is actually inserted in onResume() - see applyInsertText() - } - break; - case REQUEST_CODE_SAVE_AS: - if (resultCode == RESULT_OK && data != null) { - // Set the new file name - mUri = data.getData(); - if (debug) Log.d(TAG, "original: " + mOriginalContent + ", file: " + mFileContent); - mOriginalContent = mFileContent; - - updateTitleSdCard(); - } + + if (debug) + Log.d(TAG, "decrypted text received: " + decryptedText); + mDecryptedText = decryptedText; + mOriginalContent = decryptedText; + + } else { + Toast.makeText(this, R.string.decryption_failed, + Toast.LENGTH_SHORT).show(); + Log.e(TAG, "decryption failed"); + + finish(); + } + break; + case REQUEST_CODE_TEXT_SELECTION_ALTERNATIVE: + if (resultCode == RESULT_OK && data != null) { + // Insert result at current cursor position: + mApplyText = data.getStringExtra(NotepadIntents.EXTRA_TEXT); + mApplyTextBefore = data + .getStringExtra(NotepadIntents.EXTRA_TEXT_BEFORE_SELECTION); + mApplyTextAfter = data + .getStringExtra(NotepadIntents.EXTRA_TEXT_AFTER_SELECTION); + + // Text is actually inserted in onResume() - see + // applyInsertText() + } + break; + case REQUEST_CODE_SAVE_AS: + if (resultCode == RESULT_OK && data != null) { + // Set the new file name + mUri = data.getData(); + if (debug) + Log.d(TAG, "original: " + mOriginalContent + ", file: " + + mFileContent); + mOriginalContent = mFileContent; + + updateTitleSdCard(); + } } } -} \ No newline at end of file +} diff --git a/NotePad/src/org/openintents/notepad/NotePad.java b/NotePad/src/org/openintents/notepad/NotePad.java index 0b75440..37df749 100644 --- a/NotePad/src/org/openintents/notepad/NotePad.java +++ b/NotePad/src/org/openintents/notepad/NotePad.java @@ -35,19 +35,22 @@ public final class NotePad { public static final String AUTHORITY = "org.openintents.notepad"; // This class cannot be instantiated - private NotePad() {} + private NotePad() { + } /** * Notes table */ public static final class Notes implements BaseColumns { // This class cannot be instantiated - private Notes() {} + private Notes() { + } /** * The content:// style URL for this table */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes"); + public static final Uri CONTENT_URI = Uri.parse("content://" + + AUTHORITY + "/notes"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of notes. @@ -55,90 +58,119 @@ private Notes() {} public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.openintents.notepad.note"; /** - * The MIME type of a {@link #CONTENT_URI} sub-directory of a single note. + * The MIME type of a {@link #CONTENT_URI} sub-directory of a single + * note. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.openintents.notepad.note"; /** * The title of the note - * <P>Type: TEXT</P> + * <P> + * Type: TEXT + * </P> */ public static final String TITLE = "title"; /** * The note itself - * <P>Type: TEXT</P> + * <P> + * Type: TEXT + * </P> */ public static final String NOTE = "note"; /** * The timestamp for when the note was created - * <P>Type: INTEGER (long from System.curentTimeMillis())</P> + * <P> + * Type: INTEGER (long from System.curentTimeMillis()) + * </P> */ public static final String CREATED_DATE = "created"; /** * The timestamp for when the note was last modified - * <P>Type: INTEGER (long from System.curentTimeMillis())</P> + * <P> + * Type: INTEGER (long from System.curentTimeMillis()) + * </P> */ public static final String MODIFIED_DATE = "modified"; /** - * Tags associated with a note. - * Multiple tags are separated by commas. - * <P>Type: TEXT</P> + * Tags associated with a note. Multiple tags are separated by commas. + * <P> + * Type: TEXT + * </P> + * * @since 1.1.0 */ public static final String TAGS = "tags"; /** - * Whether the note is encrypted. - * 0 = not encrypted. 1 = encrypted. - * <P>Type: INTEGER</P> + * Whether the note is encrypted. 0 = not encrypted. 1 = encrypted. + * <P> + * Type: INTEGER + * </P> + * * @since 1.1.0 */ public static final String ENCRYPTED = "encrypted"; /** * A theme URI. - * <P>Type: TEXT</P> + * <P> + * Type: TEXT + * </P> + * * @since 1.1.0 */ public static final String THEME = "theme"; - - /** - * A R.color.id - * <P>Type: INT</P> - * @since 1.3.0 - */ - public static final String COLOR = "color"; - + /** * The starting position of the selection in the note. - * <p>TYPE: INTEGER</p> + * <p> + * TYPE: INTEGER + * </p> + * * @since 1.2.3 */ public static final String SELECTION_START = "selection_start"; - + /** * The ending position of the selection in the note. - * <p>TYPE: INTEGER</p> + * <p> + * TYPE: INTEGER + * </p> + * * @since 1.2.3 */ public static final String SELECTION_END = "selection_end"; - + /** - * The scroll position in the list expressed as scrollY/height - * TODO Implement. - * <p>TYPE: REAL</p> + * The scroll position in the list expressed as scrollY/height TODO + * Implement. + * <p> + * TYPE: REAL + * </p> + * * @since 1.2.3 */ public static final String SCROLL_POSITION = "scroll_position"; /** - * Support sort orders. The "sort order" in the preferences - * is an index into this array. + * A color id + * <P> + * Type: INTEGER + * </P> + * + * @since 1.3.2 + */ + public static final String COLOR = "color"; + + /** + * Support sort orders. The "sort order" in the preferences is an index + * into this array. */ - public static final String[] SORT_ORDERS = {"title ASC", "title DESC", "modified DESC", "modified ASC", "created DESC", "created ASC"}; + public static final String[] SORT_ORDERS = { "title ASC", "title DESC", + "modified DESC", "modified ASC", "created DESC", "created ASC" }; } } diff --git a/NotePad/src/org/openintents/notepad/NotePadProvider.java b/NotePad/src/org/openintents/notepad/NotePadProvider.java index 4e8b2e8..686cd11 100644 --- a/NotePad/src/org/openintents/notepad/NotePadProvider.java +++ b/NotePad/src/org/openintents/notepad/NotePadProvider.java @@ -16,7 +16,6 @@ package org.openintents.notepad; - import java.util.HashMap; import org.openintents.intents.ProviderIntents; @@ -55,6 +54,7 @@ public class NotePadProvider extends ContentProvider { * <li>Version 2 (1.0.0 - 1.0.2): title, note, created_date, modified_date</li> * <li>Version 3 (1.1.0 - 1.2.3): tags, encrypted, theme</li> * <li>Version 4 (1.2.3 - ): selection_start, selection_end</li> + * <li>Version 5 (1.3 - ): color</li> * </ul> */ private static final int DATABASE_VERSION = 5; @@ -78,24 +78,23 @@ private static class DatabaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " (" + db.execSQL("CREATE TABLE " + + NOTES_TABLE_NAME + + " (" // Version 2: - + Notes._ID + " INTEGER PRIMARY KEY," - + Notes.TITLE + " TEXT," - + Notes.NOTE + " TEXT," - + Notes.CREATED_DATE + " INTEGER," - + Notes.MODIFIED_DATE + " INTEGER," + + Notes._ID + " INTEGER PRIMARY KEY," + Notes.TITLE + + " TEXT," + Notes.NOTE + " TEXT," + Notes.CREATED_DATE + + " INTEGER," + Notes.MODIFIED_DATE + + " INTEGER," // Version 3: - + Notes.TAGS + " TEXT," - + Notes.ENCRYPTED + " INTEGER," + + Notes.TAGS + " TEXT," + Notes.ENCRYPTED + " INTEGER," + Notes.THEME + " TEXT," // Version 4: - + Notes.SELECTION_START + " INTEGER," - + Notes.SELECTION_END + " INTEGER," - + Notes.SCROLL_POSITION + " REAL," + + Notes.SELECTION_START + " INTEGER," + Notes.SELECTION_END + + " INTEGER," + Notes.SCROLL_POSITION + " REAL," // Version 5: - + Notes.COLOR + " INTEGER" - + ");"); + + Notes.COLOR+ " INTEGER);" + ); } @Override @@ -104,60 +103,68 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + newVersion + "."); if (newVersion > oldVersion) { // Upgrade - switch(oldVersion) { - case 2: - // Upgrade from version 2 to 3. - // It seems SQLite3 only allows to add one column at a time, - // so we need three SQL statements: - try { - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " - + Notes.TAGS + " TEXT;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " - + Notes.ENCRYPTED + " INTEGER;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " - + Notes.THEME + " TEXT;"); - } catch (SQLException e) { - Log.e(TAG, "Error executing SQL: ", e); - // If the error is "duplicate column name" then everything is fine, - // as this happens after upgrading 2->3, then downgrading 3->2, - // and then upgrading again 2->3. - } - // fall through for further upgrades. - - case 3: - // Upgrade from version 3 to 4 - try { - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " - + Notes.SELECTION_START + " INTEGER;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " - + Notes.SELECTION_END + " INTEGER;"); - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " - + Notes.SCROLL_POSITION + " REAL;"); - } catch (SQLException e) { - Log.e(TAG, "Error executing SQL: ", e); - } - - case 4: - // add more columns here - try { - db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " - + Notes.COLOR + " INTEGER;"); - } catch (SQLException e) { - Log.e(TAG, "Error executing SQL: ", e); - } - break; - case 5: - // add more columns here - break; - - default: - Log.w(TAG, "Unknown version " + oldVersion + ". Creating new database."); - db.execSQL("DROP TABLE IF EXISTS notes"); - onCreate(db); + switch (oldVersion) { + case 2: + // Upgrade from version 2 to 3. + // It seems SQLite3 only allows to add one column at a time, + // so we need three SQL statements: + try { + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + + " ADD COLUMN " + Notes.TAGS + " TEXT;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + + " ADD COLUMN " + Notes.ENCRYPTED + + " INTEGER;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + + " ADD COLUMN " + Notes.THEME + " TEXT;"); + } catch (SQLException e) { + Log.e(TAG, "Error executing SQL: ", e); + // If the error is "duplicate column name" then + // everything is fine, + // as this happens after upgrading 2->3, then + // downgrading 3->2, + // and then upgrading again 2->3. + } + // fall through for further upgrades. + + case 3: + // Upgrade from version 3 to 4 + try { + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + + " ADD COLUMN " + Notes.SELECTION_START + + " INTEGER;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + + " ADD COLUMN " + Notes.SELECTION_END + + " INTEGER;"); + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + + " ADD COLUMN " + Notes.SCROLL_POSITION + + " REAL;"); + } catch (SQLException e) { + Log.e(TAG, "Error executing SQL: ", e); + } + + case 4: + try { + db.execSQL("ALTER TABLE " + NOTES_TABLE_NAME + " ADD COLUMN " + + Notes.COLOR + " INTEGER;"); + } catch (SQLException e) { + Log.e(TAG, "Error executing SQL: ", e); + } + // fall through for further upgrades. + + case 5: + // add more columns here + break; + + default: + Log.w(TAG, "Unknown version " + oldVersion + + ". Creating new database."); + db.execSQL("DROP TABLE IF EXISTS notes"); + onCreate(db); } } else { // newVersion <= oldVersion // Downgrade - Log.w(TAG, "Don't know how to downgrade. Will not touch database and hope they are compatible."); + Log.w(TAG, + "Don't know how to downgrade. Will not touch database and hope they are compatible."); // Do nothing. } } @@ -172,24 +179,24 @@ public boolean onCreate() { } @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { + public Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch (sUriMatcher.match(uri)) { - case NOTES: - qb.setTables(NOTES_TABLE_NAME); - qb.setProjectionMap(sNotesProjectionMap); - break; - - case NOTE_ID: - qb.setTables(NOTES_TABLE_NAME); - qb.setProjectionMap(sNotesProjectionMap); - qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1)); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); + case NOTES: + qb.setTables(NOTES_TABLE_NAME); + qb.setProjectionMap(sNotesProjectionMap); + break; + + case NOTE_ID: + qb.setTables(NOTES_TABLE_NAME); + qb.setProjectionMap(sNotesProjectionMap); + qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1)); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); } // If no sort order is specified use the default @@ -202,9 +209,11 @@ public Cursor query(Uri uri, String[] projection, String selection, String[] sel // Get the database and run the query SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); + Cursor c = qb.query(db, projection, selection, selectionArgs, null, + null, orderBy); - // Tell the cursor what uri to watch, so it knows when its source data changes + // Tell the cursor what uri to watch, so it knows when its source data + // changes c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @@ -212,14 +221,14 @@ public Cursor query(Uri uri, String[] projection, String selection, String[] sel @Override public String getType(Uri uri) { switch (sUriMatcher.match(uri)) { - case NOTES: - return Notes.CONTENT_TYPE; + case NOTES: + return Notes.CONTENT_TYPE; - case NOTE_ID: - return Notes.CONTENT_ITEM_TYPE; + case NOTE_ID: + return Notes.CONTENT_ITEM_TYPE; - default: - throw new IllegalArgumentException("Unknown URI " + uri); + default: + throw new IllegalArgumentException("Unknown URI " + uri); } } @@ -250,33 +259,35 @@ public Uri insert(Uri uri, ContentValues initialValues) { if (values.containsKey(NotePad.Notes.TITLE) == false) { Resources r = Resources.getSystem(); - values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled)); + values.put(NotePad.Notes.TITLE, + r.getString(android.R.string.untitled)); } if (values.containsKey(NotePad.Notes.NOTE) == false) { values.put(NotePad.Notes.NOTE, ""); } - - if(values.containsKey(Notes.SELECTION_START) == false) { + + if (values.containsKey(Notes.SELECTION_START) == false) { values.put(Notes.SELECTION_START, 0); } - - if(values.containsKey(Notes.SELECTION_END) == false) { + + if (values.containsKey(Notes.SELECTION_END) == false) { values.put(Notes.SELECTION_END, 0); } - - if(values.containsKey(Notes.SCROLL_POSITION) == false) { + + if (values.containsKey(Notes.SCROLL_POSITION) == false) { values.put(Notes.SCROLL_POSITION, 0.0); } if(values.containsKey(Notes.COLOR) == false) { values.put(Notes.COLOR, -1); } - + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values); if (rowId > 0) { - Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId); + Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, + rowId); getContext().getContentResolver().notifyChange(noteUri, null); Intent intent = new Intent(ProviderIntents.ACTION_INSERTED); @@ -295,22 +306,24 @@ public int delete(Uri uri, String where, String[] whereArgs) { int count; long[] affectedRows = null; switch (sUriMatcher.match(uri)) { - case NOTES: - affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, where, whereArgs); - count = db.delete(NOTES_TABLE_NAME, where, whereArgs); - break; - - case NOTE_ID: - String noteId = uri.getPathSegments().get(1); - String whereString = Notes._ID + "=" + noteId - + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""); - - affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, whereString, whereArgs); - count = db.delete(NOTES_TABLE_NAME, whereString, whereArgs); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); + case NOTES: + affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, + where, whereArgs); + count = db.delete(NOTES_TABLE_NAME, where, whereArgs); + break; + + case NOTE_ID: + String noteId = uri.getPathSegments().get(1); + String whereString = Notes._ID + "=" + noteId + + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""); + + affectedRows = ProviderUtils.getAffectedRows(db, NOTES_TABLE_NAME, + whereString, whereArgs); + count = db.delete(NOTES_TABLE_NAME, whereString, whereArgs); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); @@ -324,22 +337,27 @@ public int delete(Uri uri, String where, String[] whereArgs) { } @Override - public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { + public int update(Uri uri, ContentValues values, String where, + String[] whereArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; switch (sUriMatcher.match(uri)) { - case NOTES: - count = db.update(NOTES_TABLE_NAME, values, where, whereArgs); - break; - - case NOTE_ID: - String noteId = uri.getPathSegments().get(1); - count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId - + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); + case NOTES: + count = db.update(NOTES_TABLE_NAME, values, where, whereArgs); + break; + + case NOTE_ID: + String noteId = uri.getPathSegments().get(1); + count = db.update(NOTES_TABLE_NAME, values, + Notes._ID + + "=" + + noteId + + (!TextUtils.isEmpty(where) ? " AND (" + where + + ')' : ""), whereArgs); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesList.java b/NotePad/src/org/openintents/notepad/noteslist/NotesList.java index c301f7d..32da65d 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesList.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesList.java @@ -32,8 +32,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Locale; - +import java.util.Locale; import org.openintents.distribution.DistributionLibraryListActivity; import org.openintents.distribution.DownloadOIAppDialog; @@ -92,7 +91,8 @@ * the intent if there is one, otherwise defaults to displaying the contents of * the {@link NotePadProvider} */ -public class NotesList extends DistributionLibraryListActivity implements ListView.OnScrollListener, OnDismissListener { +public class NotesList extends DistributionLibraryListActivity implements + ListView.OnScrollListener, OnDismissListener { private static final String TAG = "NotesList"; private static final boolean debug = false; @@ -103,11 +103,13 @@ public class NotesList extends DistributionLibraryListActivity implements ListVi private static final int MENU_ITEM_ENCRYPT = Menu.FIRST + 5; private static final int MENU_ITEM_UNENCRYPT = Menu.FIRST + 6; private static final int MENU_ITEM_EDIT_TAGS = Menu.FIRST + 7; - //private static final int MENU_ITEM_SAVE = Menu.FIRST + 8; + // private static final int MENU_ITEM_SAVE = Menu.FIRST + 8; private static final int MENU_OPEN = Menu.FIRST + 9; private static final int MENU_SETTINGS = Menu.FIRST + 10; private static final int MENU_SEARCH = Menu.FIRST + 11; - private static final int MENU_DISTRIBUTION_START = Menu.FIRST + 100; // MUST BE LAST + private static final int MENU_DISTRIBUTION_START = Menu.FIRST + 100; // MUST + // BE + // LAST private static final String BUNDLE_LAST_FILTER = "last_filter"; @@ -120,7 +122,7 @@ public class NotesList extends DistributionLibraryListActivity implements ListVi private final static int CATEGORY_ALTERNATIVE_GLOBAL = 1; private static final int REQUEST_CODE_DECRYPT_TITLE = 3; - //private static final int REQUEST_CODE_UNENCRYPT_NOTE = 4; + // private static final int REQUEST_CODE_UNENCRYPT_NOTE = 4; private static final int REQUEST_CODE_OPEN = 5; private static final int DIALOG_TAGS = 1; @@ -140,30 +142,32 @@ public class NotesList extends DistributionLibraryListActivity implements ListVi private boolean mDecryptionFailed; private boolean mDecryptionSucceeded; - + private static boolean mActionBarAvailable; - + static { try { WrapActionBar.checkAvailable(); mActionBarAvailable = true; - } catch(Throwable t){ + } catch (Throwable t) { mActionBarAvailable = false; } } AdapterView.AdapterContextMenuInfo mContextMenuInfo; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (debug) { - Log.d(TAG, "onCreate() " + (savedInstanceState == null ? "(no bundle)" : "(with bundle)")); + Log.d(TAG, "onCreate() " + + (savedInstanceState == null ? "(no bundle)" + : "(with bundle)")); } - mDistribution.setFirst(MENU_DISTRIBUTION_START, DIALOG_DISTRIBUTION_START); + mDistribution.setFirst(MENU_DISTRIBUTION_START, + DIALOG_DISTRIBUTION_START); // Check whether EULA has been accepted // or information about new version can be presented. @@ -179,8 +183,8 @@ protected void onCreate(Bundle savedInstanceState) { if (intent.getData() == null) { intent.setData(Notes.CONTENT_URI); } - - //show loading + + // show loading requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); requestWindowFeature(Window.FEATURE_PROGRESS); @@ -200,20 +204,17 @@ protected void onCreate(Bundle savedInstanceState) { */ /* - // Perform a managed query. The Activity will handle closing and - // requerying the cursor - // when needed. - Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, - null, Notes.DEFAULT_SORT_ORDER); - - /* - // Used to map notes entries from the database to views - SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, - R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, - new int[] { android.R.id.text1 }); - * / - mAdapter = new NotesListCursorAdapter(this, cursor, getIntent()); - setListAdapter(mAdapter); + * // Perform a managed query. The Activity will handle closing and // + * requerying the cursor // when needed. Cursor cursor = + * managedQuery(getIntent().getData(), PROJECTION, null, null, + * Notes.DEFAULT_SORT_ORDER); + * + * /* // Used to map notes entries from the database to views + * SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + * R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, new + * int[] { android.R.id.text1 }); / mAdapter = new + * NotesListCursorAdapter(this, cursor, getIntent()); + * setListAdapter(mAdapter); */ getListView().setOnScrollListener(this); @@ -226,8 +227,10 @@ protected void onCreate(Bundle savedInstanceState) { // Restore information for context menu, for opening "Tags" dialog. if (savedInstanceState.containsKey(BUNDLE_CONTEXTMENUINFO_ID)) { long id = savedInstanceState.getLong(BUNDLE_CONTEXTMENUINFO_ID); - int position = savedInstanceState.getInt(BUNDLE_CONTEXTMENUINFO_POSITION); - mContextMenuInfo = new AdapterView.AdapterContextMenuInfo(null, position, id); + int position = savedInstanceState + .getInt(BUNDLE_CONTEXTMENUINFO_POSITION); + mContextMenuInfo = new AdapterView.AdapterContextMenuInfo(null, + position, id); } } @@ -254,23 +257,23 @@ public void onChanged() { }); Spinner s = (Spinner) findViewById(R.id.tagselection); - s.setOnItemSelectedListener( - new AdapterView.OnItemSelectedListener() { + s.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { - NotesList.this.updateQuery(); - decryptDelayed(); - } + public void onItemSelected(AdapterView<?> arg0, View arg1, + int arg2, long arg3) { + NotesList.this.updateQuery(); + decryptDelayed(); + } - public void onNothingSelected(AdapterView<?> arg0) { + public void onNothingSelected(AdapterView<?> arg0) { - } - }); + } + }); mDecryptionFailed = false; mDecryptionSucceeded = false; - //disable the progressbar when done. + // disable the progressbar when done. setProgressBarIndeterminateVisibility(false); setProgressBarVisibility(false); } @@ -282,10 +285,7 @@ protected void updateTagList() { Uri notesUri = getIntent().getData(); Cursor managedCursor = getContentResolver().query(notesUri, - new String[]{Notes.TAGS, Notes.ENCRYPTED}, - null, - null, - null); + new String[] { Notes.TAGS, Notes.ENCRYPTED }, null, null, null); if (managedCursor.moveToFirst()) { do { @@ -311,7 +311,8 @@ protected void updateTagList() { Collections.sort(taglist, Collator.getInstance(Locale.getDefault())); taglist.add(0, getString(R.string.all_notes)); Spinner s = (Spinner) findViewById(R.id.tagselection); - ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, taglist); + ArrayAdapter adapter = new ArrayAdapter(this, + android.R.layout.simple_spinner_item, taglist); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); s.setAdapter(adapter); @@ -326,15 +327,15 @@ protected void updateTagList() { @Override protected void onResume() { super.onResume(); - if (debug) Log.d(TAG, "onResume()"); + if (debug) + Log.d(TAG, "onResume()"); NotesListCursor.mSuspendQueries = false; - //mCursorUtils.registerContentObserver(mListContentObserver); - //mCursorUtils.registerDataSetObserver(mListDatasetObserver); + // mCursorUtils.registerContentObserver(mListContentObserver); + // mCursorUtils.registerDataSetObserver(mListDatasetObserver); checkAdapter(); - if (!mDecryptionFailed) { decryptDelayed(); } else { @@ -344,66 +345,56 @@ protected void onResume() { if (mDecryptionSucceeded) { NotesListCursor.mLoggedIn = true; - if (debug) Log.d(TAG, "onResume: logged in"); + if (debug) + Log.d(TAG, "onResume: logged in"); } IntentFilter filter = new IntentFilter(); filter.addAction(CryptoIntents.ACTION_CRYPTO_LOGGED_OUT); registerReceiver(mBroadcastReceiver, filter); - // getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); } - /* - ContentObserver mListContentObserver = new ContentObserver(mHandler) { - - @Override - public boolean deliverSelfNotifications() { - Log.i(TAG, "NotesList:mListContentObserver: deliverSelfNotifications"); - return super.deliverSelfNotifications(); - } - - @Override - public void onChange(boolean arg0) { - Log.i(TAG, "NotesList:mListContentObserver: onChange"); - //mCursorListFilter.requery(); - updateTagList(); - - super.onChange(arg0); - } - }; - - DataSetObserver mListDatasetObserver = new DataSetObserver() { - - @Override - public void onChanged() { - Log.i(TAG, "mListDatasetObserver: onChanged"); - super.onChanged(); - } - - @Override - public void onInvalidated() { - Log.i(TAG, "mListDatasetObserver: onInvalidated"); - super.onInvalidated(); - } - }; + /* + * ContentObserver mListContentObserver = new ContentObserver(mHandler) { + * + * @Override public boolean deliverSelfNotifications() { Log.i(TAG, + * "NotesList:mListContentObserver: deliverSelfNotifications"); return + * super.deliverSelfNotifications(); } + * + * @Override public void onChange(boolean arg0) { Log.i(TAG, + * "NotesList:mListContentObserver: onChange"); + * //mCursorListFilter.requery(); updateTagList(); + * + * super.onChange(arg0); } }; + * + * DataSetObserver mListDatasetObserver = new DataSetObserver() { + * + * @Override public void onChanged() { Log.i(TAG, + * "mListDatasetObserver: onChanged"); super.onChanged(); } + * + * @Override public void onInvalidated() { Log.i(TAG, + * "mListDatasetObserver: onInvalidated"); super.onInvalidated(); } + * + * }; */ private void checkAdapter() { if (mAdapter == null) { // Perform a managed query. The Activity will handle closing and // requerying the cursor // when needed. - //Cursor cursor = getContentResolver().query(getIntent().getData(), NotesListCursorUtils.PROJECTION, null, - // null, Notes.DEFAULT_SORT_ORDER); + // Cursor cursor = getContentResolver().query(getIntent().getData(), + // NotesListCursorUtils.PROJECTION, null, + // null, Notes.DEFAULT_SORT_ORDER); Cursor cursor = mCursorUtils.query(null, null); /* - // Used to map notes entries from the database to views - SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, - R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, - new int[] { android.R.id.text1 }); + * // Used to map notes entries from the database to views + * SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + * R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, + * new int[] { android.R.id.text1 }); */ mAdapter = new NotesListCursorAdapter(this, cursor, mCursorUtils); setListAdapter(mAdapter); @@ -421,17 +412,18 @@ protected void updateQuery() { Spinner s = (Spinner) findViewById(R.id.tagselection); - if ( s.getSelectedItemPosition() == 0 ) { + if (s.getSelectedItemPosition() == 0) { mSelectedTag = null; } else { mSelectedTag = (String) s.getSelectedItem(); } - //if (mLastFilter != null || mSelectedTag != null) { - Cursor cursor = mAdapter.runQueryOnBackgroundThread(mLastFilter, mSelectedTag); + // if (mLastFilter != null || mSelectedTag != null) { + Cursor cursor = mAdapter.runQueryOnBackgroundThread(mLastFilter, + mSelectedTag); mAdapter.changeCursor(cursor); - //} -} + // } + } @Override protected void onPause() { @@ -439,32 +431,32 @@ protected void onPause() { mLastFilter = mCursorUtils.mCurrentFilter; - // Deactivating the cursor leads to flickering whenever some // encrypted information is retrieved. // Cursor c = mAdapter.getCursor(); - //if (c != null) { - // c.deactivate(); - //} + // if (c != null) { + // c.deactivate(); + // } - //mCursorUtils.unregisterDataSetObserver(mListDatasetObserver); - //mCursorUtils.unregisterContentObserver(mListContentObserver); + // mCursorUtils.unregisterDataSetObserver(mListDatasetObserver); + // mCursorUtils.unregisterContentObserver(mListContentObserver); unregisterReceiver(mBroadcastReceiver); - // After unregistering broadcastreceiver, the logged in state is not clear. + // After unregistering broadcastreceiver, the logged in state is not + // clear. NotesListCursor.mLoggedIn = false; - if (debug) Log.d(TAG, "onPause: logged out"); + if (debug) + Log.d(TAG, "onPause: logged out"); - // No need wasting a lot of time doing queries when external applications change the + // No need wasting a lot of time doing queries when external + // applications change the // database - we requery in onResume anyway. NotesListCursor.mSuspendQueries = true; mDecryptionFailed = false; mDecryptionSucceeded = false; } - - @Override protected void onDestroy() { // TODO Auto-generated method stub @@ -472,7 +464,6 @@ protected void onDestroy() { } - @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -481,16 +472,17 @@ protected void onSaveInstanceState(Bundle outState) { if (mContextMenuInfo != null) { outState.putLong(BUNDLE_CONTEXTMENUINFO_ID, mContextMenuInfo.id); - outState.putInt(BUNDLE_CONTEXTMENUINFO_POSITION, mContextMenuInfo.position); + outState.putInt(BUNDLE_CONTEXTMENUINFO_POSITION, + mContextMenuInfo.position); } } - @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - - MenuItem insertItem = menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert); + + MenuItem insertItem = menu.add(0, MENU_ITEM_INSERT, 0, + R.string.menu_insert); insertItem.setShortcut('1', 'i'); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Icon for holo theme @@ -498,21 +490,22 @@ public boolean onCreateOptionsMenu(Menu menu) { } else { insertItem.setIcon(android.R.drawable.ic_menu_add); } - //Show the delete icon when there is an actionbar - if(mActionBarAvailable){ + // Show the delete icon when there is an actionbar + if (mActionBarAvailable) { WrapActionBar.showIfRoom(insertItem); - TextView notext=(TextView)findViewById(R.id.empty); + TextView notext = (TextView) findViewById(R.id.empty); notext.setText(R.string.no_notes_actionbar); } - menu.add(0, MENU_SEARCH, 0, R.string.menu_search).setShortcut('2', - 's').setIcon(android.R.drawable.ic_menu_search); + menu.add(0, MENU_SEARCH, 0, R.string.menu_search).setShortcut('2', 's') + .setIcon(android.R.drawable.ic_menu_search); - menu.add(0, MENU_OPEN, 0, R.string.menu_open_from_sdcard).setShortcut('3', - 'o').setIcon(R.drawable.ic_menu_folder); + menu.add(0, MENU_OPEN, 0, R.string.menu_open_from_sdcard) + .setShortcut('3', 'o').setIcon(R.drawable.ic_menu_folder); - menu.add(0, MENU_SETTINGS, 0, R.string.settings).setIcon( - android.R.drawable.ic_menu_preferences).setShortcut('9', 's'); + menu.add(0, MENU_SETTINGS, 0, R.string.settings) + .setIcon(android.R.drawable.ic_menu_preferences) + .setShortcut('9', 's'); // Add distribution menu items last. mDistribution.onCreateOptionsMenu(menu); @@ -522,15 +515,17 @@ public boolean onCreateOptionsMenu(Menu menu) { // actions found here, but this allows other applications to extend // our menu with their own actions. Intent intent = new Intent(null, getIntent().getData()); - if (debug) Log.i(TAG, "Building options menu for: " + intent.getDataString()); + if (debug) + Log.i(TAG, "Building options menu for: " + intent.getDataString()); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); - //menu - // .addIntentOptions(CATEGORY_ALTERNATIVE_GLOBAL, 0, 0, - // new ComponentName(this, NotesList.class), null, intent, - // 0, null); + // menu + // .addIntentOptions(CATEGORY_ALTERNATIVE_GLOBAL, 0, 0, + // new ComponentName(this, NotesList.class), null, intent, + // 0, null); // Workaround to add icons: - MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, menu); + MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, + menu); menu2.addIntentOptions(CATEGORY_ALTERNATIVE_GLOBAL, 0, 0, new ComponentName(this, NotesList.class), null, intent, 0, null); @@ -560,13 +555,14 @@ public boolean onPrepareOptionsMenu(Menu menu) { // ... is followed by whatever other actions are available... Intent intent = new Intent(null, uri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); - //menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, - // specifics, intent, 0, items); + // menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, + // specifics, intent, 0, items); // Workaround to add icons: - MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons(this, menu); - menu2.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, - null, specifics, intent, 0, items); + MenuIntentOptionsWithIcons menu2 = new MenuIntentOptionsWithIcons( + this, menu); + menu2.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, + specifics, intent, 0, items); // Give a shortcut to the edit action. if (items[0] != null) { @@ -582,18 +578,18 @@ public boolean onPrepareOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case MENU_ITEM_INSERT: - insertNewNote(); - return true; - case MENU_SEARCH: - search(); - return true; - case MENU_OPEN: - openFromSdCard(); - return true; - case MENU_SETTINGS: - showNotesListSettings(); - return true; + case MENU_ITEM_INSERT: + insertNewNote(); + return true; + case MENU_SEARCH: + search(); + return true; + case MENU_OPEN: + openFromSdCard(); + return true; + case MENU_SETTINGS: + showNotesListSettings(); + return true; } return super.onOptionsItemSelected(item); } @@ -622,7 +618,8 @@ private void openFromSdCard() { Uri uri = FileUriUtils.getUri(directory); Intent i = new Intent(this, DialogHostingActivity.class); - i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, DialogHostingActivity.DIALOG_ID_OPEN); + i.putExtra(DialogHostingActivity.EXTRA_DIALOG_ID, + DialogHostingActivity.DIALOG_ID_OPEN); i.setData(uri); startActivityForResult(i, REQUEST_CODE_OPEN); } @@ -644,13 +641,14 @@ public void onCreateContextMenu(ContextMenu menu, View view, return; } - Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), - info.id); + Uri noteUri = ContentUris + .withAppendedId(getIntent().getData(), info.id); long encrypted = cursor.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); // Setup the menu header - menu.setHeaderTitle(cursor.getString(NotesListCursor.COLUMN_INDEX_TITLE)); + menu.setHeaderTitle(cursor + .getString(NotesListCursor.COLUMN_INDEX_TITLE)); menu.add(0, MENU_ITEM_EDIT_TAGS, 0, R.string.menu_edit_tags); @@ -660,7 +658,7 @@ public void onCreateContextMenu(ContextMenu menu, View view, menu.add(0, MENU_ITEM_SHARE, 0, R.string.menu_share); // Added automatically through manifest: - //menu.add(0, MENU_ITEM_SAVE, 0, R.string.menu_save_to_sdcard); + // menu.add(0, MENU_ITEM_SAVE, 0, R.string.menu_save_to_sdcard); menu.add(0, MENU_ITEM_ENCRYPT, 0, R.string.menu_encrypt); } else { @@ -676,7 +674,8 @@ public void onCreateContextMenu(ContextMenu menu, View view, Intent intent = new Intent(null, noteUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, - new ComponentName(this, NotesList.class), null, intent, 0, null); + new ComponentName(this, NotesList.class), null, intent, 0, + null); } } @@ -684,34 +683,35 @@ public void onCreateContextMenu(ContextMenu menu, View view, @Override public boolean onContextItemSelected(MenuItem item) { try { - mContextMenuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); + mContextMenuInfo = (AdapterView.AdapterContextMenuInfo) item + .getMenuInfo(); } catch (ClassCastException e) { Log.e(TAG, "bad menuInfo", e); return false; } switch (item.getItemId()) { - case MENU_ITEM_DELETE: { - showDialog(DIALOG_DELETE); - //mAdapter.getCursor().requery(); - return true; - } - case MENU_ITEM_SHARE: - sendNoteByEmail(mContextMenuInfo.id); - return true; - case MENU_ITEM_ENCRYPT: - encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_ENCRYPT); - return true; - case MENU_ITEM_UNENCRYPT: - encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_DECRYPT); - return true; - case MENU_ITEM_EDIT_TAGS: - editTags(); - - return true; - //case MENU_ITEM_SAVE: - // saveToSdCard(); - // return true; + case MENU_ITEM_DELETE: { + showDialog(DIALOG_DELETE); + // mAdapter.getCursor().requery(); + return true; + } + case MENU_ITEM_SHARE: + sendNoteByEmail(mContextMenuInfo.id); + return true; + case MENU_ITEM_ENCRYPT: + encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_ENCRYPT); + return true; + case MENU_ITEM_UNENCRYPT: + encryptNote(mContextMenuInfo.id, CryptoIntents.ACTION_DECRYPT); + return true; + case MENU_ITEM_EDIT_TAGS: + editTags(); + + return true; + // case MENU_ITEM_SAVE: + // saveToSdCard(); + // return true; } return false; } @@ -733,8 +733,10 @@ private void sendNoteByEmail(long id) { content = c.getString(1); } - if (debug) Log.i(TAG, "Title to send: " + title); - if (debug) Log.i(TAG, "Content to send: " + content); + if (debug) + Log.i(TAG, "Title to send: " + title); + if (debug) + Log.i(TAG, "Content to send: " + content); SendNote.sendNote(this, title, content); } @@ -749,8 +751,10 @@ private void encryptNote(long id, String action) { Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), id); // getContentResolver().(noteUri, null, null); - Cursor c = getContentResolver().query(noteUri, - new String[] { NotePad.Notes.TITLE, NotePad.Notes.NOTE, NotePad.Notes.TAGS, NotePad.Notes.ENCRYPTED }, null, + Cursor c = getContentResolver().query( + noteUri, + new String[] { NotePad.Notes.TITLE, NotePad.Notes.NOTE, + NotePad.Notes.TAGS, NotePad.Notes.ENCRYPTED }, null, null, PreferenceActivity.getSortOrderFromPrefs(this)); String title = ""; @@ -766,22 +770,21 @@ private void encryptNote(long id, String action) { } if (action.equals(CryptoIntents.ACTION_ENCRYPT) && encrypted != 0) { - Toast.makeText(this, - R.string.already_encrypted, - Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.already_encrypted, Toast.LENGTH_SHORT) + .show(); return; } if (action.equals(CryptoIntents.ACTION_DECRYPT) && encrypted == 0) { - Toast.makeText(this, - R.string.not_encrypted, - Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.not_encrypted, Toast.LENGTH_SHORT) + .show(); return; } Intent i = new Intent(this, EncryptActivity.class); i.putExtra(PrivateNotePadIntents.EXTRA_ACTION, action); - i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, EncryptActivity.getCryptoStringArray(text, title, tags)); + i.putExtra(CryptoIntents.EXTRA_TEXT_ARRAY, + EncryptActivity.getCryptoStringArray(text, title, tags)); i.putExtra(PrivateNotePadIntents.EXTRA_URI, noteUri.toString()); startActivity(i); } @@ -790,57 +793,48 @@ private void editTags() { showDialog(DIALOG_TAGS); } - private File getSdCardPath() { - return android.os.Environment - .getExternalStorageDirectory(); + return android.os.Environment.getExternalStorageDirectory(); } private void showNotesListSettings() { startActivity(new Intent(this, PreferenceActivity.class)); } - - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, - int totalItemCount) { + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { } - public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { - case OnScrollListener.SCROLL_STATE_IDLE: - Log.i(TAG, "idle"); - mAdapter.mBusy = false; - - if (!NotesListCursor.mEncryptedStringList.isEmpty()) { - String encryptedString = NotesListCursor.mEncryptedStringList.remove(0); - Log.i(TAG, "Decrypt idle: " + encryptedString); - decryptTitle(encryptedString); - } - /* - int first = view.getFirstVisiblePosition(); - int count = view.getChildCount(); - for (int i=0; i<count; i++) { - NotesListItemView t = (NotesListItemView)view.getChildAt(i); - String encryptedTitle = (String) t.getTag(); - if (encryptedTitle != null) { - // Retrieve decrypted title - decryptTitle(encryptedTitle); - t.setTag(null); - - // decrypt one item at a time. - break; - } - } - */ - - break; - case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: - mAdapter.mBusy = true; - break; - case OnScrollListener.SCROLL_STATE_FLING: - mAdapter.mBusy = true; - break; + case OnScrollListener.SCROLL_STATE_IDLE: + Log.i(TAG, "idle"); + mAdapter.mBusy = false; + + if (!NotesListCursor.mEncryptedStringList.isEmpty()) { + String encryptedString = NotesListCursor.mEncryptedStringList + .remove(0); + Log.i(TAG, "Decrypt idle: " + encryptedString); + decryptTitle(encryptedString); + } + /* + * int first = view.getFirstVisiblePosition(); int count = + * view.getChildCount(); for (int i=0; i<count; i++) { + * NotesListItemView t = (NotesListItemView)view.getChildAt(i); + * String encryptedTitle = (String) t.getTag(); if (encryptedTitle + * != null) { // Retrieve decrypted title + * decryptTitle(encryptedTitle); t.setTag(null); + * + * // decrypt one item at a time. break; } } + */ + + break; + case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: + mAdapter.mBusy = true; + break; + case OnScrollListener.SCROLL_STATE_FLING: + mAdapter.mBusy = true; + break; } } @@ -882,7 +876,8 @@ public void decryptTitle(String encryptedTitle) { intent.setAction(CryptoIntents.ACTION_DECRYPT); if (encryptedTitle != null) { intent.putExtra(CryptoIntents.EXTRA_TEXT, encryptedTitle); - intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, encryptedTitle); + intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, + encryptedTitle); } intent.putExtra(CryptoIntents.EXTRA_PROMPT, false); @@ -892,75 +887,72 @@ public void decryptTitle(String encryptedTitle) { } catch (ActivityNotFoundException e) { mDecryptionFailed = true; /* - Toast.makeText(this, - R.string.decryption_failed, - Toast.LENGTH_SHORT).show(); + * Toast.makeText(this, R.string.decryption_failed, + * Toast.LENGTH_SHORT).show(); */ Log.e(TAG, "failed to invoke encrypt"); } } - @Override protected Dialog onCreateDialog(int id) { switch (id) { - case DIALOG_TAGS: - TagsDialog td = new TagsDialog(this); - td.setOnDismissListener(this); - return td; - //return new TagsDialog(this); - case DIALOG_GET_FROM_MARKET: - return new DownloadOIAppDialog(this, - DownloadOIAppDialog.OI_SAFE); - case DIALOG_DELETE: - return new DeleteConfirmationDialog(this, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), - mContextMenuInfo.id); - getContentResolver().delete(noteUri, null, null); - updateTagList(); - } - }).create(); + case DIALOG_TAGS: + TagsDialog td = new TagsDialog(this); + td.setOnDismissListener(this); + return td; + // return new TagsDialog(this); + case DIALOG_GET_FROM_MARKET: + return new DownloadOIAppDialog(this, DownloadOIAppDialog.OI_SAFE); + case DIALOG_DELETE: + return new DeleteConfirmationDialog(this, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + Uri noteUri = ContentUris.withAppendedId( + getIntent().getData(), mContextMenuInfo.id); + getContentResolver().delete(noteUri, null, null); + updateTagList(); + } + }).create(); } return super.onCreateDialog(id); } - @Override protected void onPrepareDialog(int id, Dialog dialog) { - if (debug) Log.d(TAG, "onPrepareDialog()"); + if (debug) + Log.d(TAG, "onPrepareDialog()"); switch (id) { - case DIALOG_TAGS: - TagsDialog d = (TagsDialog) dialog; - Uri uri = ContentUris.withAppendedId(getIntent().getData(), mContextMenuInfo.id); - - Cursor c = mAdapter.getCursor(); - c.moveToPosition(mContextMenuInfo.position); - String tags = c.getString(NotesListCursor.COLUMN_INDEX_TAGS); - long encrypted = c.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); - - d.setUri(uri); - d.setTags(tags); - d.setEncrypted(encrypted); - - String[] taglist = getTaglist(c); - d.setTagList(taglist); - - break; - case DIALOG_GET_FROM_MARKET: - DownloadOIAppDialog.onPrepareDialog(this, dialog); - break; + case DIALOG_TAGS: + TagsDialog d = (TagsDialog) dialog; + Uri uri = ContentUris.withAppendedId(getIntent().getData(), + mContextMenuInfo.id); + + Cursor c = mAdapter.getCursor(); + c.moveToPosition(mContextMenuInfo.position); + String tags = c.getString(NotesListCursor.COLUMN_INDEX_TAGS); + long encrypted = c.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); + + d.setUri(uri); + d.setTags(tags); + d.setEncrypted(encrypted); + + String[] taglist = getTaglist(c); + d.setTagList(taglist); + + break; + case DIALOG_GET_FROM_MARKET: + DownloadOIAppDialog.onPrepareDialog(this, dialog); + break; } } - - public void onDismiss(DialogInterface dialog) - { - if(dialog instanceof TagsDialog) - { + + public void onDismiss(DialogInterface dialog) { + if (dialog instanceof TagsDialog) { updateTagList(); } } @@ -968,7 +960,8 @@ public void onDismiss(DialogInterface dialog) /** * Create list of tags. * - * Tags for notes can be comma-separated. Here we create a list of the unique tags. + * Tags for notes can be comma-separated. Here we create a list of the + * unique tags. * * @param c * @return @@ -994,7 +987,7 @@ String[] getTaglist(Cursor c) { // 1. Convert HashSet to String list. ArrayList<String> list = new ArrayList<String>(); list.addAll(tagset); - // 2. Sort the String list + // 2. Sort the String list Collections.sort(list); // 3. Convert it to String array return list.toArray(new String[0]); @@ -1009,22 +1002,24 @@ protected void onListItemClick(ListView l, View v, int position, long id) { long encrypted = c.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); - String encryptedTitle = c.getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); + String encryptedTitle = c + .getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); // are we in decrypted mode? - //Log.i(TAG, "Encrypted title: " + encryptedTitle); + // Log.i(TAG, "Encrypted title: " + encryptedTitle); String title = c.getString(NotesListCursor.COLUMN_INDEX_TITLE); - //Log.i(TAG, "title: " + title); + // Log.i(TAG, "title: " + title); if (encrypted != 0) { if (!TextUtils.isEmpty(encryptedTitle)) { // Try to decrypt first - //Log.i(TAG, "Decrypt first"); + // Log.i(TAG, "Decrypt first"); Intent intent = new Intent(); intent.setAction(CryptoIntents.ACTION_DECRYPT); intent.putExtra(CryptoIntents.EXTRA_TEXT, encryptedTitle); - intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, encryptedTitle); + intent.putExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT, + encryptedTitle); intent.putExtra(CryptoIntents.EXTRA_PROMPT, true); @@ -1033,9 +1028,10 @@ protected void onListItemClick(ListView l, View v, int position, long id) { } catch (ActivityNotFoundException e) { mDecryptionFailed = true; - /*Toast.makeText(this, - R.string.decryption_failed, - Toast.LENGTH_SHORT).show();*/ + /* + * Toast.makeText(this, R.string.decryption_failed, + * Toast.LENGTH_SHORT).show(); + */ showDialog(DIALOG_GET_FROM_MARKET); Log.e(TAG, "failed to invoke encrypt"); } @@ -1051,7 +1047,7 @@ protected void onListItemClick(ListView l, View v, int position, long id) { // The caller is waiting for us to return a note selected by // the user. The have clicked on one, so return it now. setResult(RESULT_OK, new Intent().setData(uri)); - finish (); + finish(); } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) { Intent data = new Intent(Intent.ACTION_VIEW); data.setData(uri); @@ -1067,10 +1063,10 @@ protected void onListItemClick(ListView l, View v, int position, long id) { Intent shortcut = new Intent(Intent.ACTION_CREATE_SHORTCUT); shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, data); - Intent.ShortcutIconResource sir = Intent.ShortcutIconResource.fromContext(this, R.drawable.ic_launcher_notepad); + Intent.ShortcutIconResource sir = Intent.ShortcutIconResource + .fromContext(this, R.drawable.ic_launcher_notepad); shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, sir); - setResult(RESULT_OK, shortcut); finish(); } else { @@ -1079,101 +1075,99 @@ protected void onListItemClick(ListView l, View v, int position, long id) { } } + protected void onActivityResult(int requestCode, int resultCode, + Intent intent) { + if (debug) + Log.i(TAG, "Received requestCode " + requestCode + ", resultCode " + + resultCode); + switch (requestCode) { + case REQUEST_CODE_DECRYPT_TITLE: + if (resultCode == RESULT_OK && intent != null) { + String decryptedText = intent + .getStringExtra(CryptoIntents.EXTRA_TEXT); + String encryptedText = intent + .getStringExtra(PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT); + + if (encryptedText != null) { + // Log.i(TAG, "Encrypted text is not passed properly."); + // return; + + // Add decrypted text to hash: + NotesListCursor.mEncryptedStringHashMap.put(encryptedText, + decryptedText); + + if (debug) + Log.i(TAG, "Decrypted: " + encryptedText + " -> " + + decryptedText); + } + mDecryptionSucceeded = true; + NotesListCursor.mLoggedIn = true; + if (debug) + Log.d(TAG, "onActivity: logged in"); - protected void onActivityResult (int requestCode, int resultCode, Intent intent) { - if (debug) Log.i(TAG, "Received requestCode " + requestCode + ", resultCode " + resultCode); - switch(requestCode) { - case REQUEST_CODE_DECRYPT_TITLE: - if (resultCode == RESULT_OK && intent != null) { - String decryptedText = intent.getStringExtra (CryptoIntents.EXTRA_TEXT); - String encryptedText = intent.getStringExtra (PrivateNotePadIntents.EXTRA_ENCRYPTED_TEXT); - - if (encryptedText != null) { - //Log.i(TAG, "Encrypted text is not passed properly."); - //return; - - - // Add decrypted text to hash: - NotesListCursor.mEncryptedStringHashMap.put(encryptedText, decryptedText); - - if (debug) Log.i(TAG, "Decrypted: " + encryptedText + " -> " + decryptedText); - } - mDecryptionSucceeded = true; - NotesListCursor.mLoggedIn = true; - if (debug) Log.d(TAG, "onActivity: logged in"); - - // decrypt the next string. - - decryptDelayed(); + // decrypt the next string. + decryptDelayed(); + } else { + mDecryptionFailed = true; + setProgressBarIndeterminateVisibility(false); + } + break; + case REQUEST_CODE_OPEN: + if (resultCode == RESULT_OK && intent != null) { + // File name should be in Uri: + File filename = FileUriUtils.getFile(intent.getData()); + + if (filename.exists() && !filename.isDirectory()) { + // Open file in note editor + Intent i = new Intent(this, NoteEditor.class); + i.setAction(Intent.ACTION_VIEW); + i.setData(intent.getData()); + startActivity(i); } else { - mDecryptionFailed = true; - setProgressBarIndeterminateVisibility(false); - } - break; - case REQUEST_CODE_OPEN: - if (resultCode == RESULT_OK && intent != null) { - // File name should be in Uri: - File filename = FileUriUtils.getFile(intent.getData()); - - if (filename.exists() && !filename.isDirectory()) { - // Open file in note editor - Intent i = new Intent(this, NoteEditor.class); - i.setAction(Intent.ACTION_VIEW); - i.setData(intent.getData()); - startActivity(i); - } else { - Toast.makeText(this, R.string.file_not_found, - Toast.LENGTH_SHORT).show(); - } + Toast.makeText(this, R.string.file_not_found, + Toast.LENGTH_SHORT).show(); } - break; - - /* - case REQUEST_CODE_UNENCRYPT_NOTE: - if (resultCode == RESULT_OK && data != null) { - String[] decryptedTextArray = data.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); - String decryptedText = decryptedTextArray[0]; - String decryptedTitle = decryptedTextArray[1]; - - String uristring = data.getStringExtra(NotePadIntents.EXTRA_URI); - - Uri uri = null; - if (uristring != null) { - uri = Uri.parse(uristring); - } else { - Log.i(TAG, "Wrong extra uri"); - Toast.makeText(this, - "Encrypted information incomplete", - Toast.LENGTH_SHORT).show(); - return; - } - - // Write this to content provider: - - ContentValues values = new ContentValues(); - values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); - values.put(Notes.TITLE, decryptedTitle); - values.put(Notes.NOTE, decryptedText); - values.put(Notes.ENCRYPTED, 0); - - //Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), id); - Uri noteUri = getIntent().getData(); - - getContentResolver().update(uri, values, null, null); - - } else { - setProgressBarIndeterminateVisibility(false); - } - break; - */ + } + break; + + /* + * case REQUEST_CODE_UNENCRYPT_NOTE: if (resultCode == RESULT_OK && data + * != null) { String[] decryptedTextArray = + * data.getStringArrayExtra(CryptoIntents.EXTRA_TEXT_ARRAY); String + * decryptedText = decryptedTextArray[0]; String decryptedTitle = + * decryptedTextArray[1]; + * + * String uristring = data.getStringExtra(NotePadIntents.EXTRA_URI); + * + * Uri uri = null; if (uristring != null) { uri = Uri.parse(uristring); + * } else { Log.i(TAG, "Wrong extra uri"); Toast.makeText(this, + * "Encrypted information incomplete", Toast.LENGTH_SHORT).show(); + * return; } + * + * // Write this to content provider: + * + * ContentValues values = new ContentValues(); + * values.put(Notes.MODIFIED_DATE, System.currentTimeMillis()); + * values.put(Notes.TITLE, decryptedTitle); values.put(Notes.NOTE, + * decryptedText); values.put(Notes.ENCRYPTED, 0); + * + * //Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), + * id); Uri noteUri = getIntent().getData(); + * + * getContentResolver().update(uri, values, null, null); + * + * } else { setProgressBarIndeterminateVisibility(false); } break; + */ } } private void saveFile(Uri uri, File file) { - if (debug) Log.i(TAG, "Saving file: uri: " + uri + ", file: " + file); - Cursor c = getContentResolver().query(uri, new String[] {Notes.ENCRYPTED, Notes.NOTE}, null, null, null); + if (debug) + Log.i(TAG, "Saving file: uri: " + uri + ", file: " + file); + Cursor c = getContentResolver().query(uri, + new String[] { Notes.ENCRYPTED, Notes.NOTE }, null, null, null); if (c != null && c.getCount() > 0) { c.moveToFirst(); @@ -1181,12 +1175,14 @@ private void saveFile(Uri uri, File file) { String note = c.getString(1); if (encrypted == 0) { // Save to file - if (debug) Log.d(TAG, "Save unencrypted file."); + if (debug) + Log.d(TAG, "Save unencrypted file."); writeToFile(file, note); } else { // decrypt first, then save to file - if (debug) Log.d(TAG, "Save encrypted file."); + if (debug) + Log.d(TAG, "Save encrypted file."); } } else { Log.e(TAG, "Error saving file: Uri not valid: " + uri); @@ -1199,8 +1195,8 @@ void writeToFile(File file, String text) { BufferedWriter out = new BufferedWriter(fstream); out.write(text); out.close(); - Toast.makeText(this, R.string.note_saved, - Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.note_saved, Toast.LENGTH_SHORT) + .show(); } catch (IOException e) { Toast.makeText(this, R.string.error_writing_file, Toast.LENGTH_SHORT).show(); @@ -1211,7 +1207,8 @@ void writeToFile(File file, String text) { BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { - if (debug) Log.i(TAG, "flush decrypted data"); + if (debug) + Log.i(TAG, "flush decrypted data"); NotesListCursor.flushDecryptedStringHashMap(); mAdapter.getCursor().requery(); } @@ -1219,19 +1216,14 @@ public void onReceive(Context context, Intent intent) { }; /* - - // Note: onKeyDown is never called, because the - // list filter consumes the event before. - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_DEL) { - // Delete the currently selected item (if any). - Log.i(TAG, "Selected item: " + getSelectedItemId()); - - return true; - } - return false; - } + * + * // Note: onKeyDown is never called, because the // list filter consumes + * the event before. + * + * @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if + * (keyCode == KeyEvent.KEYCODE_DEL) { // Delete the currently selected item + * (if any). Log.i(TAG, "Selected item: " + getSelectedItemId()); + * + * return true; } return false; } */ } diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java index 5a32e39..af4f0e8 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursor.java @@ -30,26 +30,24 @@ public class NotesListCursor extends OpenMatrixCursor { /** * The columns we are interested in from the database */ - protected static final String[] PROJECTION_DB = new String[] { - Notes._ID, // 0 - Notes.TITLE, // 1 - Notes.TAGS, // 2 - Notes.ENCRYPTED, // 3 - Notes.COLOR // 4 + protected static final String[] PROJECTION_DB = new String[] { Notes._ID, // 0 + Notes.TITLE, // 1 + Notes.TAGS, // 2 + Notes.ENCRYPTED, // 3 + Notes.COLOR // 4 }; /** * This cursors' columns */ - public static final String[] PROJECTION = new String[] { - Notes._ID, // 0 - Notes.TITLE, // 1 - Notes.TAGS, // 2 - Notes.ENCRYPTED, // 3 - TITLE_DECRYPTED, // 4 - TAGS_DECRYPTED, // 5 - Notes.COLOR // 6 + public static final String[] PROJECTION = new String[] { Notes._ID, // 0 + Notes.TITLE, // 1 + Notes.TAGS, // 2 + Notes.ENCRYPTED, // 3 + TITLE_DECRYPTED, // 4 + TAGS_DECRYPTED, // 5 + Notes.COLOR // 6 }; public static final int COLUMN_INDEX_ID = 0; @@ -69,11 +67,11 @@ public class NotesListCursor extends OpenMatrixCursor { Context mContext; Intent mIntent; - //OpenMatrixCursor mCursor; + // OpenMatrixCursor mCursor; /** - * A database cursor that corresponds to the encrypted data of - * the current cursor (that contains also decrypted information). + * A database cursor that corresponds to the encrypted data of the current + * cursor (that contains also decrypted information). */ Cursor mDbCursor; @@ -83,13 +81,15 @@ public class NotesListCursor extends OpenMatrixCursor { /** * Map encrypted titles to decrypted ones. */ - public static HashMap<String,String> mEncryptedStringHashMap = new HashMap<String,String>(); + public static HashMap<String, String> mEncryptedStringHashMap = new HashMap<String, String>(); /** - * List containing all encrypted strings. These are decrypted one at a time while idle. - * The list is synchronized because background threads may add items to it. + * List containing all encrypted strings. These are decrypted one at a time + * while idle. The list is synchronized because background threads may add + * items to it. */ - public static List<String> mEncryptedStringList = Collections.synchronizedList(new LinkedList<String>()); + public static List<String> mEncryptedStringList = Collections + .synchronizedList(new LinkedList<String>()); public boolean mContainsEncryptedStrings; @@ -102,7 +102,6 @@ public NotesListCursor(Context context, Intent intent) { } - // TODO: Replace new Handler() by mHandler from NotesList somehow. ContentObserver mContentObserver = new ContentObserver(new Handler()) { @@ -114,17 +113,18 @@ public boolean deliverSelfNotifications() { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - if (debug) Log.d(TAG, "NoteListCursor changed: " + selfChange); + if (debug) + Log.d(TAG, "NoteListCursor changed: " + selfChange); if (!mSuspendQueries) { - if (debug) Log.d(TAG, "NoteListCursor requery()"); + if (debug) + Log.d(TAG, "NoteListCursor requery()"); requery(); } } }; - @Override public boolean requery() { runQuery(mCurrentFilter, mSelectedTag); @@ -132,8 +132,7 @@ public boolean requery() { return super.requery(); } - - /** + /** * Return a new cursor with decrypted information. * * @param constraint @@ -144,21 +143,22 @@ public Cursor query(CharSequence constraint, String tag) { return cursor; } - /** + /** * Return a query with decrypted information on the current cursor. * * @param constraint */ private void runQuery(CharSequence constraint, String tag) { - // We have to query all items and return a new object, because notes may be encrypted. + // We have to query all items and return a new object, because notes may + // be encrypted. if (constraint != null) { mCurrentFilter = constraint.toString(); } else { mCurrentFilter = null; } - if(tag != null) { + if (tag != null) { mSelectedTag = tag; } else { mSelectedTag = null; @@ -169,16 +169,17 @@ private void runQuery(CharSequence constraint, String tag) { mDbCursor.close(); mDbCursor = null; } - mDbCursor = mContext.getContentResolver().query(mIntent.getData(), PROJECTION_DB, - null, null, PreferenceActivity.getSortOrderFromPrefs(mContext)); - + mDbCursor = mContext.getContentResolver().query(mIntent.getData(), + PROJECTION_DB, null, null, + PreferenceActivity.getSortOrderFromPrefs(mContext)); // Register content observer mDbCursor.registerContentObserver(mContentObserver); - if (debug) Log.d(TAG, "Cursor count: " + mDbCursor.getCount()); + if (debug) + Log.d(TAG, "Cursor count: " + mDbCursor.getCount()); - //mCursor = new OpenMatrixCursor(PROJECTION, dbcursor.getCount()); + // mCursor = new OpenMatrixCursor(PROJECTION, dbcursor.getCount()); reset(); mContainsEncryptedStrings = false; @@ -203,10 +204,12 @@ private void runQuery(CharSequence constraint, String tag) { String titleDecrypted = mEncryptedStringHashMap.get(title); if (titleDecrypted != null) { - if (debug) Log.d(TAG, "got title: " + titleDecrypted); + if (debug) + Log.d(TAG, "got title: " + titleDecrypted); title = titleDecrypted; } else { - if (debug) Log.d(TAG, "decrypt title later."); + if (debug) + Log.d(TAG, "decrypt title later."); // decrypt later addForEncryption(title); @@ -220,10 +223,12 @@ private void runQuery(CharSequence constraint, String tag) { if (tags != null) { String tagsDecrypted = mEncryptedStringHashMap.get(tags); if (tagsDecrypted != null) { - if (debug) Log.d(TAG, "got tags: " + tagsDecrypted); + if (debug) + Log.d(TAG, "got tags: " + tagsDecrypted); tags = tagsDecrypted; } else { - if (debug) Log.d(TAG, "decrypt tags later."); + if (debug) + Log.d(TAG, "decrypt tags later."); // decrypt later addForEncryption(tags); @@ -236,7 +241,8 @@ private void runQuery(CharSequence constraint, String tag) { } if (!mLoggedIn) { - if (debug) Log.d(TAG, "not logged in."); + if (debug) + Log.d(TAG, "not logged in."); // suppress all decrypted output title = encryptedlabel; tags = ""; @@ -245,11 +251,13 @@ private void runQuery(CharSequence constraint, String tag) { boolean addrow = false; - if (TextUtils.isEmpty(mCurrentFilter) && TextUtils.isEmpty(mSelectedTag)) { + if (TextUtils.isEmpty(mCurrentFilter) + && TextUtils.isEmpty(mSelectedTag)) { // Add all rows if there is no filter. addrow = true; } else if (skipEncrypted) { - if (debug) Log.d(TAG, "skipEncrypted)"); + if (debug) + Log.d(TAG, "skipEncrypted)"); addrow = false; } else { // test the filter @@ -267,20 +275,22 @@ private void runQuery(CharSequence constraint, String tag) { List<String> tagList = new ArrayList<String>(); if (!TextUtils.isEmpty(tags)) { - for(String tagString: tags.split(",")) { - if(tagString.trim().length() != 0) { + for (String tagString : tags.split(",")) { + if (tagString.trim().length() != 0) { tagList.add(tagString.trim()); } } } - if ( TextUtils.isEmpty(mCurrentFilter) ) { + if (TextUtils.isEmpty(mCurrentFilter)) { addrow = tagList.contains(mSelectedTag.trim()); - } else if ( TextUtils.isEmpty(mSelectedTag) ) { - addrow = searchstring.contains(" " + mCurrentFilter.toUpperCase()); + } else if (TextUtils.isEmpty(mSelectedTag)) { + addrow = searchstring.contains(" " + + mCurrentFilter.toUpperCase()); } else { - addrow = searchstring.contains(" " + mCurrentFilter.toUpperCase()) && - tagList.contains(mSelectedTag.trim()); + addrow = searchstring.contains(" " + + mCurrentFilter.toUpperCase()) + && tagList.contains(mSelectedTag.trim()); } if (!addrow && encrypted != 0) { @@ -299,14 +309,15 @@ private void runQuery(CharSequence constraint, String tag) { mContainsEncryptedStrings = true; } - Object[] row = new Object[] {id, title, tags, encrypted, titleEncrypted, tagsEncrypted, color}; + Object[] row = new Object[] { id, title, tags, encrypted, + titleEncrypted, tagsEncrypted, color}; addRow(row); } } } public static void flushDecryptedStringHashMap() { - mEncryptedStringHashMap = new HashMap<String,String>(); + mEncryptedStringHashMap = new HashMap<String, String>(); mLoggedIn = false; } @@ -319,7 +330,8 @@ public static void addForEncryption(String encryptedString) { public static String getNextEncryptedString() { if (!NotesListCursor.mEncryptedStringList.isEmpty()) { - String encryptedString = NotesListCursor.mEncryptedStringList.remove(0); + String encryptedString = NotesListCursor.mEncryptedStringList + .remove(0); return encryptedString; } else { return null; @@ -328,28 +340,29 @@ public static String getNextEncryptedString() { @Override public void close() { - if (debug) Log.d(TAG, "Close NotesListCursor"); + if (debug) + Log.d(TAG, "Close NotesListCursor"); super.close(); } - @Override public void deactivate() { - if (debug) Log.d(TAG, "Deactivate NotesListCursor"); + if (debug) + Log.d(TAG, "Deactivate NotesListCursor"); if (mDbCursor != null) { mDbCursor.deactivate(); } super.deactivate(); } - @Override protected void finalize() { - if (debug) Log.d(TAG, "Finalize NotesListCursor"); + if (debug) + Log.d(TAG, "Finalize NotesListCursor"); if (mDbCursor != null) { mDbCursor.unregisterContentObserver(mContentObserver); - //mDbCursor.close(); + // mDbCursor.close(); mDbCursor.deactivate(); mDbCursor.close(); mDbCursor = null; @@ -358,5 +371,4 @@ protected void finalize() { super.finalize(); } - } diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java index c4b5171..72fff81 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListCursorAdapter.java @@ -12,13 +12,13 @@ public class NotesListCursorAdapter extends CursorAdapter { Context mContext; NotesListCursor mCursorUtils; - /** * Flag for slow list adapter. */ public boolean mBusy; - public NotesListCursorAdapter(Context context, Cursor c, NotesListCursor cursorUtils) { + public NotesListCursorAdapter(Context context, Cursor c, + NotesListCursor cursorUtils) { super(context, c); mContext = context; mCursorUtils = cursorUtils; @@ -33,8 +33,10 @@ public void bindView(View view, Context context, Cursor cursor) { String title = cursor.getString(NotesListCursor.COLUMN_INDEX_TITLE); String tags = cursor.getString(NotesListCursor.COLUMN_INDEX_TAGS); long encrypted = cursor.getLong(NotesListCursor.COLUMN_INDEX_ENCRYPTED); - String titleEncrypted = cursor.getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); - String tagsEncrypted = cursor.getString(NotesListCursor.COLUMN_INDEX_TAGS_ENCRYPTED); + String titleEncrypted = cursor + .getString(NotesListCursor.COLUMN_INDEX_TITLE_ENCRYPTED); + String tagsEncrypted = cursor + .getString(NotesListCursor.COLUMN_INDEX_TAGS_ENCRYPTED); int color = cursor.getInt(NotesListCursor.COLUMN_INDEX_COLOR + 2); nliv.setEncrypted(encrypted); @@ -45,81 +47,57 @@ public void bindView(View view, Context context, Cursor cursor) { nliv.mTagsEncrypted = tagsEncrypted; nliv.setColor(color); - /* - if (encrypted == 0) { - // Not encrypted: - nliv.setTitle(title); - nliv.setTags(tags); - // Null tag means the view has the correct data - nliv.setTag(null); - } else { - // encrypted - String decrypted = mTitleHashMap.get(title); - if (decrypted != null) { - nliv.setTitle(decrypted); - nliv.setTags(tags); - // Null tag means the view has the correct data - nliv.setTag(null); - } else { - nliv.setTitle(mContext.getString(R.string.encrypted)); - nliv.setTags(tags); - // Non-null tag means the view still needs to load it's data - // Tag contains a pointer to a string with the encrypted title. - nliv.setTag(title); - } - /* - if (!mBusy) { - nliv.setTitle("set"); - nliv.setTitle("wow"); - // Null tag means the view has the correct data - nliv.setTag(null); - } else { - nliv.setTitle(mContext.getString(R.string.encrypted)); - nliv.setTags(tags); - // Non-null tag means the view still needs to load it's data - nliv.setTag(this); - } - * / - } + * if (encrypted == 0) { // Not encrypted: nliv.setTitle(title); + * nliv.setTags(tags); // Null tag means the view has the correct data + * nliv.setTag(null); } else { // encrypted String decrypted = + * mTitleHashMap.get(title); if (decrypted != null) { + * nliv.setTitle(decrypted); nliv.setTags(tags); // Null tag means the + * view has the correct data nliv.setTag(null); } else { + * nliv.setTitle(mContext.getString(R.string.encrypted)); + * nliv.setTags(tags); // Non-null tag means the view still needs to + * load it's data // Tag contains a pointer to a string with the + * encrypted title. nliv.setTag(title); } /* if (!mBusy) { + * nliv.setTitle("set"); nliv.setTitle("wow"); // Null tag means the + * view has the correct data nliv.setTag(null); } else { + * nliv.setTitle(mContext.getString(R.string.encrypted)); + * nliv.setTags(tags); // Non-null tag means the view still needs to + * load it's data nliv.setTag(this); } / } */ } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return new NotesListItemView(context); - } - + } /* - @Override - public Filter getFilter() { - Log.i(TAG, "Request filter"); - - return super.getFilter(); - } + * @Override public Filter getFilter() { Log.i(TAG, "Request filter"); + * + * return super.getFilter(); } */ /* - @Override - public CharSequence convertToString(Cursor cursor) { - //return super.convertToString(cursor); - - Log.i(TAG, "convertToString" + cursor.getPosition() + " / " + cursor.getCount()); - - return cursor.getString(NotesList.COLUMN_INDEX_TITLE); - } + * @Override public CharSequence convertToString(Cursor cursor) { //return + * super.convertToString(cursor); + * + * Log.i(TAG, "convertToString" + cursor.getPosition() + " / " + + * cursor.getCount()); + * + * return cursor.getString(NotesList.COLUMN_INDEX_TITLE); } */ public Cursor runQueryOnBackgroundThread(CharSequence constraint, String tag) { - //Log.i(TAG, "runQueryOnBackgroundThread " + constraint + ", " + mIntent.getData()); - + // Log.i(TAG, "runQueryOnBackgroundThread " + constraint + ", " + + // mIntent.getData()); /* - Cursor cursor = mContext.getContentResolver().query(mIntent.getData(), NotesList.PROJECTION, - "(" + Notes.TITLE + " like '" + constraint.toString() + "%' ) or (" - + Notes.TITLE + " like '% " + constraint.toString() + "%' )", - new String[] { }, Notes.DEFAULT_SORT_ORDER); + * Cursor cursor = + * mContext.getContentResolver().query(mIntent.getData(), + * NotesList.PROJECTION, "(" + Notes.TITLE + " like '" + + * constraint.toString() + "%' ) or (" + Notes.TITLE + " like '% " + + * constraint.toString() + "%' )", new String[] { }, + * Notes.DEFAULT_SORT_ORDER); */ Cursor cursor = mCursorUtils.query(constraint, tag); @@ -127,5 +105,4 @@ public Cursor runQueryOnBackgroundThread(CharSequence constraint, String tag) { return cursor; } - } diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java index 26f1cdd..290751b 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java @@ -20,7 +20,7 @@ public class NotesListItemView extends LinearLayout { Context mContext; - private MarqueeTextView mTitle; + private arqueeTextView mTitle; private TextView mTags; private ImageView mStatus; @@ -41,33 +41,26 @@ public NotesListItemView(Context context) { LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate( - R.layout.noteslist_item, this, true); + inflater.inflate(R.layout.noteslist_item, this, true); - mTitle = (MarqueeTextView) findViewById(R.id.title); + mTitle = (arqueeTextView) findViewById(R.id.title); mTags = (TextView) findViewById(R.id.info); mStatus = (ImageView) findViewById(R.id.status); } - - @Override public boolean hasFocus() { // TODO Auto-generated method stub - if(PreferenceActivity.getMarqueeFromPrefs(mContext)==true) { - mTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE); - mTitle.setMarquee(true); - } - else - { + if (PreferenceActivity.getarqueeFromPrefs(mContext) == true) { + mTitle.setEllipsize(TextUtils.TruncateAt.ARQUEE); + mTitle.setarquee(true); + } else { mTitle.setEllipsize(TextUtils.TruncateAt.END); - mTitle.setMarquee(false); + mTitle.setarquee(false); } return super.hasFocus(); } - - /** * Convenience method to set the title of a NewsView */ @@ -92,8 +85,6 @@ public void setEncrypted(long encrypted) { } } - - public void setColor(int color) { Resources res = this.getResources(); Drawable d = res.getDrawable(R.drawable.note_item_bg_yellow); @@ -113,7 +104,7 @@ public void setColor(int color) { default: break; } - - mTitle.setBackgroundDrawable(d); + + mTitle.setBackgroundDrawable(d); } } diff --git a/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java b/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java index 2144219..2a1d249 100644 --- a/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java +++ b/NotePad/src/org/openintents/notepad/wrappers/WrapActionBar.java @@ -1,6 +1,4 @@ package org.openintents.notepad.wrappers; -import org.openintents.notepad.R; - import android.app.ActionBar; import android.app.Activity; @@ -8,34 +6,33 @@ public class WrapActionBar { private ActionBar mInstance; - + static { try { Class.forName("android.app.ActionBar"); - } catch (Exception ex){ + } catch (Exception ex) { throw new RuntimeException(ex); } } - + /* calling here forces class initialization */ public static void checkAvailable() { - } - - public WrapActionBar(Activity a){ + + public WrapActionBar(Activity a) { mInstance = a.getActionBar(); } - - public void setDisplayHomeAsUpEnabled(boolean b){ + + public void setDisplayHomeAsUpEnabled(boolean b) { mInstance.setDisplayHomeAsUpEnabled(b); } - - public void setHomeButtonEnabled(boolean b){ + + public void setHomeButtonEnabled(boolean b) { mInstance.setHomeButtonEnabled(b); } - + // show an icon in the actionbar if there is room for it. - public static void showIfRoom(MenuItem item){ + public static void showIfRoom(MenuItem item) { item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } } From 536469abb1f6e16a05894b4ff92cd772982410ab Mon Sep 17 00:00:00 2001 From: Benedikt Elser <boun@gmx.de> Date: Wed, 27 Feb 2013 16:26:12 +0100 Subject: [PATCH 6/8] Was needed by my froyo device --- NotePad/res/layout/note_editor.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NotePad/res/layout/note_editor.xml b/NotePad/res/layout/note_editor.xml index 209c3c5..11fa66e 100644 --- a/NotePad/res/layout/note_editor.xml +++ b/NotePad/res/layout/note_editor.xml @@ -31,6 +31,8 @@ android:fadingEdge="none"> <view android:id="@+id/note" class="org.openintents.notepad.NoteEditor$LinedEditText" + android:singleLine="false" + android:inputType="textMultiLine" android:padding="5dip" android:layout_width="fill_parent" android:layout_height="fill_parent" From 03a54b64aeb21e3fdf7b6ac83e50b20bf2c1cb6f Mon Sep 17 00:00:00 2001 From: Benedikt Elser <boun@gmx.de> Date: Wed, 27 Feb 2013 16:27:02 +0100 Subject: [PATCH 7/8] Brown Paperbag ;) --- NotePad/AndroidManifest.xml | 2 +- .../notepad/noteslist/NotesListItemView.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/NotePad/AndroidManifest.xml b/NotePad/AndroidManifest.xml index 578983b..f68b41b 100644 --- a/NotePad/AndroidManifest.xml +++ b/NotePad/AndroidManifest.xml @@ -42,7 +42,7 @@ [10054] 1.1.1: 2009-05-16 [10052] 1.1.0: 2009-02-02 --> - <uses-sdk android:minSdkVersion="11" + <uses-sdk android:minSdkVersion="2" android:targetSdkVersion="15" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> diff --git a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java index 290751b..ae3e496 100644 --- a/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java +++ b/NotePad/src/org/openintents/notepad/noteslist/NotesListItemView.java @@ -20,7 +20,7 @@ public class NotesListItemView extends LinearLayout { Context mContext; - private arqueeTextView mTitle; + private MarqueeTextView mTitle; private TextView mTags; private ImageView mStatus; @@ -43,7 +43,7 @@ public NotesListItemView(Context context) { inflater.inflate(R.layout.noteslist_item, this, true); - mTitle = (arqueeTextView) findViewById(R.id.title); + mTitle = (MarqueeTextView) findViewById(R.id.title); mTags = (TextView) findViewById(R.id.info); mStatus = (ImageView) findViewById(R.id.status); } @@ -51,12 +51,12 @@ public NotesListItemView(Context context) { @Override public boolean hasFocus() { // TODO Auto-generated method stub - if (PreferenceActivity.getarqueeFromPrefs(mContext) == true) { - mTitle.setEllipsize(TextUtils.TruncateAt.ARQUEE); - mTitle.setarquee(true); + if (PreferenceActivity.getMarqueeFromPrefs(mContext) == true) { + mTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE); + mTitle.setMarquee(true); } else { mTitle.setEllipsize(TextUtils.TruncateAt.END); - mTitle.setarquee(false); + mTitle.setMarquee(false); } return super.hasFocus(); } From e483301dc1298f4cd62b310c7b16770783351daa Mon Sep 17 00:00:00 2001 From: Benedikt Elser <boun@gmx.de> Date: Wed, 27 Feb 2013 16:27:13 +0100 Subject: [PATCH 8/8] Remove README --- README.md | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index bf1be54..0000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -notepad -======= - -Fork of the excellent OpenIntents Notepad, to add some some MIUI pastel color love. - -Uses some code/pngs from https://github.com/ebraminio/miuinotes -