notecipher / app / src / info / guardianproject / notepadbot / NoteCipher.java @ d572d209
History | View | Annotate | Download (16.4 KB)
1 |
/*
|
---|---|
2 |
* Copyright (C) 2008 Google Inc.
|
3 |
*
|
4 |
* Licensed under the Apache License, Version 2.0 (the "License")savedInstanceState;
|
5 |
* you may not use this file except in compliance with the License.
|
6 |
* You may obtain a copy of the License at
|
7 |
*
|
8 |
* http://www.apache.org/licenses/LICENSE-2.0
|
9 |
*
|
10 |
* Unless required by applicable law or agreed to in writing, software
|
11 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 |
* See the License for the specific language governing permissions and
|
14 |
* limitations under the License.
|
15 |
*/
|
16 |
|
17 |
package info.guardianproject.notepadbot; |
18 |
|
19 |
import android.app.AlertDialog; |
20 |
import android.content.ContentResolver; |
21 |
import android.content.Context; |
22 |
import android.content.DialogInterface; |
23 |
import android.content.Intent; |
24 |
import android.content.res.Configuration; |
25 |
import android.database.Cursor; |
26 |
import android.net.Uri; |
27 |
import android.os.Bundle; |
28 |
import android.support.v4.app.LoaderManager; |
29 |
import android.support.v4.content.CursorLoader; |
30 |
import android.support.v4.content.Loader; |
31 |
import android.support.v4.widget.SimpleCursorAdapter; |
32 |
import android.util.Log; |
33 |
import android.view.ContextMenu; |
34 |
import android.view.ContextMenu.ContextMenuInfo; |
35 |
import android.view.MotionEvent; |
36 |
import android.view.View; |
37 |
import android.view.View.OnTouchListener; |
38 |
import android.widget.AdapterView; |
39 |
import android.widget.AdapterView.AdapterContextMenuInfo; |
40 |
import android.widget.AdapterView.OnItemClickListener; |
41 |
import android.widget.ListView; |
42 |
import android.widget.TextView; |
43 |
import android.widget.Toast; |
44 |
|
45 |
import com.actionbarsherlock.app.SherlockFragmentActivity; |
46 |
import com.actionbarsherlock.view.Menu; |
47 |
import com.actionbarsherlock.view.MenuItem; |
48 |
|
49 |
import info.guardianproject.cacheword.CacheWordActivityHandler; |
50 |
import info.guardianproject.cacheword.ICacheWordSubscriber; |
51 |
|
52 |
import net.sqlcipher.database.SQLiteDatabase; |
53 |
|
54 |
import java.io.FileNotFoundException; |
55 |
import java.io.IOException; |
56 |
import java.io.InputStream; |
57 |
|
58 |
public class NoteCipher extends SherlockFragmentActivity implements ICacheWordSubscriber { |
59 |
|
60 |
private static final int ACTIVITY_CREATE = 0; |
61 |
private static final int ACTIVITY_EDIT = 1; |
62 |
|
63 |
private static final int INSERT_ID = Menu.FIRST; |
64 |
private static final int DELETE_ID = Menu.FIRST + 1; |
65 |
private static final int REKEY_ID = Menu.FIRST + 2; |
66 |
private static final int SHARE_ID = Menu.FIRST + 3; |
67 |
private static final int VIEW_ID = Menu.FIRST + 4; |
68 |
private static final int LOCK_ID = Menu.FIRST + 5; |
69 |
private static final int SETTINGS_ID = Menu.FIRST + 6; |
70 |
|
71 |
private NotesDbAdapter mDbHelper;
|
72 |
|
73 |
private Uri dataStream;
|
74 |
|
75 |
private CacheWordActivityHandler mCacheWord;
|
76 |
|
77 |
private ListView notesListView; |
78 |
private SimpleCursorAdapter notesCursorAdapter;
|
79 |
|
80 |
/** Called when the activity is first created. */
|
81 |
@Override
|
82 |
public void onCreate(Bundle savedInstanceState) { |
83 |
super.onCreate(savedInstanceState);
|
84 |
|
85 |
if (getIntent() != null) { |
86 |
if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
|
87 |
dataStream = (Uri) getIntent().getExtras().get(Intent.EXTRA_STREAM); |
88 |
} else {
|
89 |
dataStream = getIntent().getData(); |
90 |
} |
91 |
} |
92 |
|
93 |
SQLiteDatabase.loadLibs(this);
|
94 |
setContentView(R.layout.notes_list); |
95 |
notesListView = (ListView) findViewById(R.id.notesListView);
|
96 |
notesListView.setOnItemClickListener(new OnItemClickListener() {
|
97 |
@Override
|
98 |
public void onItemClick(AdapterView<?> ad, View v, int position, |
99 |
long id) {
|
100 |
Intent i = new Intent(getApplication(), NoteEdit.class);
|
101 |
i.putExtra(NotesDbAdapter.KEY_ROWID, id); |
102 |
startActivityForResult(i, ACTIVITY_EDIT); |
103 |
} |
104 |
}); |
105 |
registerForContextMenu(notesListView); |
106 |
mCacheWord = new CacheWordActivityHandler(this, ((App)getApplication()).getCWSettings()); |
107 |
|
108 |
// Create an array to specify the fields we want to display in the list (only TITLE)
|
109 |
String[] from = new String[] { NotesDbAdapter.KEY_TITLE }; |
110 |
|
111 |
// and an array of the fields we want to bind those fields to (in this
|
112 |
// case just text1)
|
113 |
int[] to = new int[] { R.id.row_text }; |
114 |
|
115 |
// Now create an empty simple cursor adapter that later will display the notes
|
116 |
notesCursorAdapter = new SimpleCursorAdapter(this, R.layout.notes_row, null, from, to |
117 |
, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); |
118 |
notesListView.setAdapter(notesCursorAdapter); |
119 |
} |
120 |
|
121 |
@Override
|
122 |
protected void onPause() { |
123 |
super.onPause();
|
124 |
mCacheWord.onPause(); |
125 |
} |
126 |
|
127 |
@Override
|
128 |
protected void onResume() { |
129 |
super.onResume();
|
130 |
mCacheWord.onResume(); |
131 |
} |
132 |
|
133 |
@Override
|
134 |
public void onAttachedToWindow() { |
135 |
super.onAttachedToWindow();
|
136 |
|
137 |
findViewById(R.id.listlayout).setOnTouchListener(new OnTouchListener() {
|
138 |
@Override
|
139 |
public boolean onTouch(View v, MotionEvent event) { |
140 |
|
141 |
if (mDbHelper != null && mDbHelper.isOpen()) |
142 |
createNote(); |
143 |
|
144 |
return false; |
145 |
} |
146 |
}); |
147 |
} |
148 |
|
149 |
private void closeDatabase() { |
150 |
if (mDbHelper != null) { |
151 |
mDbHelper.close(); |
152 |
mDbHelper = null;
|
153 |
} |
154 |
} |
155 |
|
156 |
private void unlockDatabase() { |
157 |
if (mCacheWord.isLocked())
|
158 |
return;
|
159 |
mDbHelper = new NotesDbAdapter(mCacheWord, this); |
160 |
try {
|
161 |
|
162 |
mDbHelper.open(); |
163 |
|
164 |
if (dataStream != null) |
165 |
importDataStream(); |
166 |
else
|
167 |
fillData(); |
168 |
|
169 |
} catch (Exception e) { |
170 |
e.printStackTrace(); |
171 |
Toast.makeText(this, getString(R.string.err_pass), Toast.LENGTH_LONG).show();
|
172 |
} |
173 |
} |
174 |
|
175 |
private void fillData() { |
176 |
if (mCacheWord.isLocked())
|
177 |
return;
|
178 |
|
179 |
getSupportLoaderManager().restartLoader(VIEW_ID, null, new LoaderManager.LoaderCallbacks<Cursor>() { |
180 |
|
181 |
@Override
|
182 |
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { |
183 |
return new NotesLoader(NoteCipher.this, mDbHelper); |
184 |
} |
185 |
|
186 |
@Override
|
187 |
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { |
188 |
notesCursorAdapter.swapCursor(cursor); |
189 |
|
190 |
TextView emptyTV = (TextView) findViewById(R.id.emptytext); |
191 |
if (notesCursorAdapter.isEmpty()) {
|
192 |
Toast.makeText(NoteCipher.this, R.string.on_start, Toast.LENGTH_LONG).show(); |
193 |
emptyTV.setText(R.string.no_notes); |
194 |
} else {
|
195 |
emptyTV.setText("");
|
196 |
} |
197 |
} |
198 |
|
199 |
@Override
|
200 |
public void onLoaderReset(Loader<Cursor> loader) { } |
201 |
}); |
202 |
} |
203 |
|
204 |
@Override
|
205 |
public boolean onCreateOptionsMenu(Menu menu) { |
206 |
super.onCreateOptionsMenu(menu);
|
207 |
menu.add(0, INSERT_ID, 0, R.string.menu_insert) |
208 |
.setIcon(R.drawable.new_content) |
209 |
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
210 |
//menu.add(0, REKEY_ID, 0, R.string.menu_rekey)
|
211 |
// .setIcon(R.drawable.key_icon)
|
212 |
// .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
213 |
menu.add(0, LOCK_ID, 0, R.string.menu_lock) |
214 |
.setIcon(R.drawable.lock) |
215 |
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
216 |
menu.add(0, SETTINGS_ID, 0, R.string.settings) |
217 |
.setIcon(R.drawable.settings) |
218 |
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
219 |
return true; |
220 |
} |
221 |
|
222 |
@Override
|
223 |
public boolean onMenuItemSelected(int featureId, MenuItem item) { |
224 |
switch (item.getItemId()) {
|
225 |
case INSERT_ID:
|
226 |
createNote(); |
227 |
return true; |
228 |
case REKEY_ID:
|
229 |
return true; |
230 |
case LOCK_ID:
|
231 |
if (!mCacheWord.isLocked())
|
232 |
mCacheWord.manuallyLock(); |
233 |
return true; |
234 |
case SETTINGS_ID:
|
235 |
startActivity(new Intent(this, Settings.class)); |
236 |
return true; |
237 |
} |
238 |
|
239 |
return super.onMenuItemSelected(featureId, item); |
240 |
} |
241 |
|
242 |
@Override
|
243 |
public void onCreateContextMenu(ContextMenu menu, View v, |
244 |
ContextMenuInfo menuInfo) { |
245 |
super.onCreateContextMenu(menu, v, menuInfo);
|
246 |
// menu.add(0, VIEW_ID, 0, R.string.menu_view);
|
247 |
menu.add(0, SHARE_ID, 0, R.string.menu_share); |
248 |
menu.add(0, DELETE_ID, 0, R.string.menu_delete); |
249 |
|
250 |
} |
251 |
|
252 |
@Override
|
253 |
public boolean onContextItemSelected(android.view.MenuItem item) { |
254 |
AdapterContextMenuInfo info; |
255 |
|
256 |
switch (item.getItemId()) {
|
257 |
case DELETE_ID:
|
258 |
info = (AdapterContextMenuInfo) item.getMenuInfo(); |
259 |
mDbHelper.deleteNote(info.id); |
260 |
fillData(); |
261 |
return true; |
262 |
case SHARE_ID:
|
263 |
info = (AdapterContextMenuInfo) item.getMenuInfo(); |
264 |
shareEntry(info.id); |
265 |
|
266 |
return true; |
267 |
case VIEW_ID:
|
268 |
info = (AdapterContextMenuInfo) item.getMenuInfo(); |
269 |
viewEntry(info.id); |
270 |
|
271 |
return true; |
272 |
} |
273 |
return super.onContextItemSelected(item); |
274 |
} |
275 |
|
276 |
private void shareEntry(final long id) { |
277 |
if (mCacheWord.isLocked())
|
278 |
return;
|
279 |
|
280 |
getSupportLoaderManager().restartLoader(SHARE_ID, null, new LoaderManager.LoaderCallbacks<Cursor>() { |
281 |
|
282 |
@Override
|
283 |
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { |
284 |
return new NoteEdit.NoteContentLoader(NoteCipher.this, mDbHelper, id); |
285 |
} |
286 |
|
287 |
@Override
|
288 |
public void onLoadFinished(Loader<Cursor> loader, Cursor note) { |
289 |
byte[] blob = note.getBlob(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_DATA)); |
290 |
String title = note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE));
|
291 |
String mimeType = note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TYPE));
|
292 |
|
293 |
if (mimeType == null) |
294 |
mimeType = "text/plain";
|
295 |
|
296 |
if (blob != null) { |
297 |
try {
|
298 |
NoteUtils.shareData(NoteCipher.this, title, mimeType, blob); |
299 |
} catch (IOException e) { |
300 |
Toast.makeText(NoteCipher.this, getString(R.string.err_export, e.getMessage()), Toast.LENGTH_LONG) |
301 |
.show(); |
302 |
} |
303 |
} else {
|
304 |
String body = note.getString( note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY) );
|
305 |
NoteUtils.shareText(NoteCipher.this, body); |
306 |
} |
307 |
note.close(); |
308 |
} |
309 |
|
310 |
@Override
|
311 |
public void onLoaderReset(Loader<Cursor> loader) { } |
312 |
}); |
313 |
} |
314 |
|
315 |
private void viewEntry(final long id) { |
316 |
if (mCacheWord.isLocked())
|
317 |
return;
|
318 |
|
319 |
getSupportLoaderManager().restartLoader(VIEW_ID, null, new LoaderManager.LoaderCallbacks<Cursor>() { |
320 |
|
321 |
@Override
|
322 |
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { |
323 |
return new NoteEdit.NoteContentLoader(NoteCipher.this, mDbHelper, id); |
324 |
} |
325 |
|
326 |
@Override
|
327 |
public void onLoadFinished(Loader<Cursor> loader, Cursor note) { |
328 |
byte[] blob = note.getBlob(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_DATA)); |
329 |
String mimeType = note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TYPE));
|
330 |
|
331 |
if (mimeType == null) |
332 |
mimeType = "text/plain";
|
333 |
|
334 |
if (blob != null) { |
335 |
String title = note.getString(
|
336 |
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)); |
337 |
|
338 |
NoteUtils.savePublicFile(NoteCipher.this, title, mimeType, blob); |
339 |
|
340 |
} |
341 |
note.close(); |
342 |
} |
343 |
|
344 |
@Override
|
345 |
public void onLoaderReset(Loader<Cursor> loader) { } |
346 |
}); |
347 |
} |
348 |
|
349 |
private void createNote() { |
350 |
if (mCacheWord.isLocked())
|
351 |
return;
|
352 |
|
353 |
Intent i = new Intent(this, NoteEdit.class); |
354 |
startActivityForResult(i, ACTIVITY_CREATE); |
355 |
} |
356 |
|
357 |
/*
|
358 |
* Called after the return from creating a new note (non-Javadoc)
|
359 |
* @see android.app.Activity#onActivityResult(int, int,
|
360 |
* android.content.Intent)
|
361 |
*/
|
362 |
@Override
|
363 |
protected void onActivityResult(int requestCode, int resultCode, |
364 |
Intent intent) { |
365 |
super.onActivityResult(requestCode, resultCode, intent);
|
366 |
|
367 |
mDbHelper = new NotesDbAdapter(mCacheWord, this); |
368 |
|
369 |
fillData(); |
370 |
} |
371 |
|
372 |
@Override
|
373 |
protected void onStop() { |
374 |
super.onStop();
|
375 |
} |
376 |
|
377 |
@Override
|
378 |
public void onConfigurationChanged(Configuration newConfig) { |
379 |
super.onConfigurationChanged(newConfig);
|
380 |
} |
381 |
|
382 |
@Override
|
383 |
protected void onSaveInstanceState(Bundle outState) { |
384 |
super.onSaveInstanceState(outState);
|
385 |
} |
386 |
|
387 |
@Override
|
388 |
protected void onDestroy() { |
389 |
super.onDestroy();
|
390 |
|
391 |
closeDatabase(); |
392 |
NoteUtils.cleanupTmp(this);
|
393 |
} |
394 |
|
395 |
private void importDataStream() { |
396 |
if (mCacheWord.isLocked())
|
397 |
return;
|
398 |
|
399 |
try {
|
400 |
ContentResolver cr = getContentResolver(); |
401 |
InputStream is = cr.openInputStream(dataStream);
|
402 |
|
403 |
String mimeType = cr.getType(dataStream);
|
404 |
|
405 |
byte[] data = NoteUtils.readBytesAndClose(is); |
406 |
|
407 |
if (data.length > NConstants.MAX_STREAM_SIZE) {
|
408 |
Toast.makeText(this, R.string.err_size, Toast.LENGTH_LONG).show();
|
409 |
} else {
|
410 |
String title = dataStream.getLastPathSegment();
|
411 |
String body = dataStream.getPath();
|
412 |
|
413 |
new NotesDbAdapter(mCacheWord, this).createNote(title, body, data, mimeType); |
414 |
|
415 |
Toast.makeText(this, getString(R.string.on_import, title), Toast.LENGTH_LONG).show();
|
416 |
|
417 |
// handleDelete();
|
418 |
|
419 |
data = null;
|
420 |
dataStream = null;
|
421 |
title = null;
|
422 |
body = null;
|
423 |
|
424 |
System.gc();
|
425 |
|
426 |
fillData(); |
427 |
} |
428 |
|
429 |
} catch (FileNotFoundException e) { |
430 |
Log.e(NConstants.TAG, e.getMessage(), e); |
431 |
|
432 |
} catch (IOException e) { |
433 |
Log.e(NConstants.TAG, e.getMessage(), e); |
434 |
|
435 |
} catch (OutOfMemoryError e) { |
436 |
Toast.makeText(this, R.string.err_size, Toast.LENGTH_LONG).show();
|
437 |
|
438 |
} finally {
|
439 |
dataStream = null;
|
440 |
|
441 |
} |
442 |
} |
443 |
|
444 |
/*
|
445 |
* Call this to delete the original image, will ask the user
|
446 |
*/
|
447 |
private void handleDelete() { |
448 |
final AlertDialog.Builder b = new AlertDialog.Builder(this); |
449 |
b.setIcon(android.R.drawable.ic_dialog_alert); |
450 |
b.setTitle(R.string.app_name); |
451 |
b.setMessage(R.string.confirm_delete); |
452 |
b.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
453 |
@Override
|
454 |
public void onClick(DialogInterface dialog, int whichButton) { |
455 |
|
456 |
// User clicked OK so go ahead and delete
|
457 |
ContentResolver cr = getContentResolver(); |
458 |
|
459 |
if (cr != null) |
460 |
cr.delete(dataStream, null, null); |
461 |
else {
|
462 |
Toast.makeText(NoteCipher.this, R.string.unable_to_delete_original, Toast.LENGTH_SHORT).show(); |
463 |
} |
464 |
|
465 |
} |
466 |
}); |
467 |
b.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
|
468 |
@Override
|
469 |
public void onClick(DialogInterface dialog, int whichButton) { |
470 |
|
471 |
} |
472 |
}); |
473 |
b.show(); |
474 |
} |
475 |
|
476 |
void showLockScreen() {
|
477 |
Intent intent = new Intent(this, LockScreenActivity.class); |
478 |
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); |
479 |
intent.putExtra("originalIntent", getIntent());
|
480 |
startActivity(intent); |
481 |
finish(); |
482 |
} |
483 |
|
484 |
void clearViewsAndLock() {
|
485 |
closeDatabase(); |
486 |
notesListView.setAdapter(null);
|
487 |
System.gc();
|
488 |
showLockScreen(); |
489 |
} |
490 |
|
491 |
@Override
|
492 |
public void onCacheWordUninitialized() { |
493 |
Log.d(NConstants.TAG, "onCacheWordUninitialized");
|
494 |
clearViewsAndLock(); |
495 |
} |
496 |
|
497 |
@Override
|
498 |
public void onCacheWordLocked() { |
499 |
Log.d(NConstants.TAG, "onCacheWordLocked");
|
500 |
clearViewsAndLock(); |
501 |
} |
502 |
|
503 |
@Override
|
504 |
public void onCacheWordOpened() { |
505 |
Log.d(NConstants.TAG, "onCacheWordOpened");
|
506 |
unlockDatabase(); |
507 |
|
508 |
if (mDbHelper.isOpen()) {
|
509 |
if (dataStream != null) |
510 |
importDataStream(); |
511 |
else
|
512 |
fillData(); |
513 |
} |
514 |
} |
515 |
|
516 |
public static class NotesLoader extends CursorLoader { |
517 |
NotesDbAdapter db; |
518 |
|
519 |
public NotesLoader(Context context) { |
520 |
super(context);
|
521 |
} |
522 |
|
523 |
public NotesLoader(Context context, NotesDbAdapter db) { |
524 |
super(context);
|
525 |
this.db = db;
|
526 |
} |
527 |
|
528 |
@Override
|
529 |
public Cursor loadInBackground() { |
530 |
if (db == null) |
531 |
return null; |
532 |
return db.fetchAllNotes();
|
533 |
} |
534 |
} |
535 |
} |