Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7859 views
1
package com.artifex.mupdfdemo;
2
3
import java.io.InputStream;
4
import java.util.concurrent.Executor;
5
6
import com.artifex.mupdfdemo.ReaderView.ViewMapper;
7
8
import android.app.Activity;
9
import android.app.AlertDialog;
10
import android.content.Context;
11
import android.content.DialogInterface;
12
import android.content.DialogInterface.OnCancelListener;
13
import android.content.Intent;
14
import android.content.SharedPreferences;
15
import android.content.res.Resources;
16
import android.database.Cursor;
17
import android.graphics.Color;
18
import android.net.Uri;
19
import android.os.Bundle;
20
import android.os.Handler;
21
import android.text.Editable;
22
import android.text.TextWatcher;
23
import android.text.method.PasswordTransformationMethod;
24
import android.view.KeyEvent;
25
import android.view.Menu;
26
import android.view.View;
27
import android.view.animation.Animation;
28
import android.view.animation.TranslateAnimation;
29
import android.view.inputmethod.EditorInfo;
30
import android.view.inputmethod.InputMethodManager;
31
import android.widget.EditText;
32
import android.widget.ImageButton;
33
import android.widget.RelativeLayout;
34
import android.widget.SeekBar;
35
import android.widget.TextView;
36
import android.widget.ViewAnimator;
37
38
class ThreadPerTaskExecutor implements Executor {
39
public void execute(Runnable r) {
40
new Thread(r).start();
41
}
42
}
43
44
public class MuPDFActivity extends Activity implements FilePicker.FilePickerSupport
45
{
46
/* The core rendering instance */
47
enum TopBarMode {Main, Search, Annot, Delete, More, Accept};
48
enum AcceptMode {Highlight, Underline, StrikeOut, Ink, CopyText};
49
50
private final int OUTLINE_REQUEST=0;
51
private final int PRINT_REQUEST=1;
52
private final int FILEPICK_REQUEST=2;
53
private MuPDFCore core;
54
private String mFileName;
55
private MuPDFReaderView mDocView;
56
private View mButtonsView;
57
private boolean mButtonsVisible;
58
private EditText mPasswordView;
59
private TextView mFilenameView;
60
private SeekBar mPageSlider;
61
private int mPageSliderRes;
62
private TextView mPageNumberView;
63
private TextView mInfoView;
64
private ImageButton mSearchButton;
65
private ImageButton mReflowButton;
66
private ImageButton mOutlineButton;
67
private ImageButton mMoreButton;
68
private TextView mAnnotTypeText;
69
private ImageButton mAnnotButton;
70
private ViewAnimator mTopBarSwitcher;
71
private ImageButton mLinkButton;
72
private TopBarMode mTopBarMode = TopBarMode.Main;
73
private AcceptMode mAcceptMode;
74
private ImageButton mSearchBack;
75
private ImageButton mSearchFwd;
76
private EditText mSearchText;
77
private SearchTask mSearchTask;
78
private AlertDialog.Builder mAlertBuilder;
79
private boolean mLinkHighlight = false;
80
private final Handler mHandler = new Handler();
81
private boolean mAlertsActive= false;
82
private boolean mReflow = false;
83
private AsyncTask<Void,Void,MuPDFAlert> mAlertTask;
84
private AlertDialog mAlertDialog;
85
private FilePicker mFilePicker;
86
87
public void createAlertWaiter() {
88
mAlertsActive = true;
89
// All mupdf library calls are performed on asynchronous tasks to avoid stalling
90
// the UI. Some calls can lead to javascript-invoked requests to display an
91
// alert dialog and collect a reply from the user. The task has to be blocked
92
// until the user's reply is received. This method creates an asynchronous task,
93
// the purpose of which is to wait of these requests and produce the dialog
94
// in response, while leaving the core blocked. When the dialog receives the
95
// user's response, it is sent to the core via replyToAlert, unblocking it.
96
// Another alert-waiting task is then created to pick up the next alert.
97
if (mAlertTask != null) {
98
mAlertTask.cancel(true);
99
mAlertTask = null;
100
}
101
if (mAlertDialog != null) {
102
mAlertDialog.cancel();
103
mAlertDialog = null;
104
}
105
mAlertTask = new AsyncTask<Void,Void,MuPDFAlert>() {
106
107
@Override
108
protected MuPDFAlert doInBackground(Void... arg0) {
109
if (!mAlertsActive)
110
return null;
111
112
return core.waitForAlert();
113
}
114
115
@Override
116
protected void onPostExecute(final MuPDFAlert result) {
117
// core.waitForAlert may return null when shutting down
118
if (result == null)
119
return;
120
final MuPDFAlert.ButtonPressed pressed[] = new MuPDFAlert.ButtonPressed[3];
121
for(int i = 0; i < 3; i++)
122
pressed[i] = MuPDFAlert.ButtonPressed.None;
123
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
124
public void onClick(DialogInterface dialog, int which) {
125
mAlertDialog = null;
126
if (mAlertsActive) {
127
int index = 0;
128
switch (which) {
129
case AlertDialog.BUTTON1: index=0; break;
130
case AlertDialog.BUTTON2: index=1; break;
131
case AlertDialog.BUTTON3: index=2; break;
132
}
133
result.buttonPressed = pressed[index];
134
// Send the user's response to the core, so that it can
135
// continue processing.
136
core.replyToAlert(result);
137
// Create another alert-waiter to pick up the next alert.
138
createAlertWaiter();
139
}
140
}
141
};
142
mAlertDialog = mAlertBuilder.create();
143
mAlertDialog.setTitle(result.title);
144
mAlertDialog.setMessage(result.message);
145
switch (result.iconType)
146
{
147
case Error:
148
break;
149
case Warning:
150
break;
151
case Question:
152
break;
153
case Status:
154
break;
155
}
156
switch (result.buttonGroupType)
157
{
158
case OkCancel:
159
mAlertDialog.setButton(AlertDialog.BUTTON2, getString(R.string.cancel), listener);
160
pressed[1] = MuPDFAlert.ButtonPressed.Cancel;
161
case Ok:
162
mAlertDialog.setButton(AlertDialog.BUTTON1, getString(R.string.okay), listener);
163
pressed[0] = MuPDFAlert.ButtonPressed.Ok;
164
break;
165
case YesNoCancel:
166
mAlertDialog.setButton(AlertDialog.BUTTON3, getString(R.string.cancel), listener);
167
pressed[2] = MuPDFAlert.ButtonPressed.Cancel;
168
case YesNo:
169
mAlertDialog.setButton(AlertDialog.BUTTON1, getString(R.string.yes), listener);
170
pressed[0] = MuPDFAlert.ButtonPressed.Yes;
171
mAlertDialog.setButton(AlertDialog.BUTTON2, getString(R.string.no), listener);
172
pressed[1] = MuPDFAlert.ButtonPressed.No;
173
break;
174
}
175
mAlertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
176
public void onCancel(DialogInterface dialog) {
177
mAlertDialog = null;
178
if (mAlertsActive) {
179
result.buttonPressed = MuPDFAlert.ButtonPressed.None;
180
core.replyToAlert(result);
181
createAlertWaiter();
182
}
183
}
184
});
185
186
mAlertDialog.show();
187
}
188
};
189
190
mAlertTask.executeOnExecutor(new ThreadPerTaskExecutor());
191
}
192
193
public void destroyAlertWaiter() {
194
mAlertsActive = false;
195
if (mAlertDialog != null) {
196
mAlertDialog.cancel();
197
mAlertDialog = null;
198
}
199
if (mAlertTask != null) {
200
mAlertTask.cancel(true);
201
mAlertTask = null;
202
}
203
}
204
205
private MuPDFCore openFile(String path)
206
{
207
int lastSlashPos = path.lastIndexOf('/');
208
mFileName = new String(lastSlashPos == -1
209
? path
210
: path.substring(lastSlashPos+1));
211
System.out.println("Trying to open "+path);
212
try
213
{
214
core = new MuPDFCore(this, path);
215
// New file: drop the old outline data
216
OutlineActivityData.set(null);
217
}
218
catch (Exception e)
219
{
220
System.out.println(e);
221
return null;
222
}
223
return core;
224
}
225
226
private MuPDFCore openBuffer(byte buffer[], String magic)
227
{
228
System.out.println("Trying to open byte buffer");
229
try
230
{
231
core = new MuPDFCore(this, buffer, magic);
232
// New file: drop the old outline data
233
OutlineActivityData.set(null);
234
}
235
catch (Exception e)
236
{
237
System.out.println(e);
238
return null;
239
}
240
return core;
241
}
242
243
/** Called when the activity is first created. */
244
@Override
245
public void onCreate(Bundle savedInstanceState)
246
{
247
super.onCreate(savedInstanceState);
248
249
mAlertBuilder = new AlertDialog.Builder(this);
250
251
if (core == null) {
252
core = (MuPDFCore)getLastNonConfigurationInstance();
253
254
if (savedInstanceState != null && savedInstanceState.containsKey("FileName")) {
255
mFileName = savedInstanceState.getString("FileName");
256
}
257
}
258
if (core == null) {
259
Intent intent = getIntent();
260
byte buffer[] = null;
261
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
262
Uri uri = intent.getData();
263
System.out.println("URI to open is: " + uri);
264
if (uri.toString().startsWith("content://")) {
265
String reason = null;
266
try {
267
InputStream is = getContentResolver().openInputStream(uri);
268
int len = is.available();
269
buffer = new byte[len];
270
is.read(buffer, 0, len);
271
is.close();
272
}
273
catch (java.lang.OutOfMemoryError e) {
274
System.out.println("Out of memory during buffer reading");
275
reason = e.toString();
276
}
277
catch (Exception e) {
278
System.out.println("Exception reading from stream: " + e);
279
280
// Handle view requests from the Transformer Prime's file manager
281
// Hopefully other file managers will use this same scheme, if not
282
// using explicit paths.
283
// I'm hoping that this case below is no longer needed...but it's
284
// hard to test as the file manager seems to have changed in 4.x.
285
try {
286
Cursor cursor = getContentResolver().query(uri, new String[]{"_data"}, null, null, null);
287
if (cursor.moveToFirst()) {
288
String str = cursor.getString(0);
289
if (str == null) {
290
reason = "Couldn't parse data in intent";
291
}
292
else {
293
uri = Uri.parse(str);
294
}
295
}
296
}
297
catch (Exception e2) {
298
System.out.println("Exception in Transformer Prime file manager code: " + e2);
299
reason = e2.toString();
300
}
301
}
302
if (reason != null) {
303
buffer = null;
304
Resources res = getResources();
305
AlertDialog alert = mAlertBuilder.create();
306
setTitle(String.format(res.getString(R.string.cannot_open_document_Reason), reason));
307
alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.dismiss),
308
new DialogInterface.OnClickListener() {
309
public void onClick(DialogInterface dialog, int which) {
310
finish();
311
}
312
});
313
alert.show();
314
return;
315
}
316
}
317
if (buffer != null) {
318
core = openBuffer(buffer, intent.getType());
319
} else {
320
String path = Uri.decode(uri.getEncodedPath());
321
if (path == null) {
322
path = uri.toString();
323
}
324
core = openFile(path);
325
}
326
SearchTaskResult.set(null);
327
}
328
if (core != null && core.needsPassword()) {
329
requestPassword(savedInstanceState);
330
return;
331
}
332
if (core != null && core.countPages() == 0)
333
{
334
core = null;
335
}
336
}
337
if (core == null)
338
{
339
AlertDialog alert = mAlertBuilder.create();
340
alert.setTitle(R.string.cannot_open_document);
341
alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.dismiss),
342
new DialogInterface.OnClickListener() {
343
public void onClick(DialogInterface dialog, int which) {
344
finish();
345
}
346
});
347
alert.setOnCancelListener(new OnCancelListener() {
348
349
@Override
350
public void onCancel(DialogInterface dialog) {
351
finish();
352
}
353
});
354
alert.show();
355
return;
356
}
357
358
createUI(savedInstanceState);
359
}
360
361
public void requestPassword(final Bundle savedInstanceState) {
362
mPasswordView = new EditText(this);
363
mPasswordView.setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
364
mPasswordView.setTransformationMethod(new PasswordTransformationMethod());
365
366
AlertDialog alert = mAlertBuilder.create();
367
alert.setTitle(R.string.enter_password);
368
alert.setView(mPasswordView);
369
alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.okay),
370
new DialogInterface.OnClickListener() {
371
public void onClick(DialogInterface dialog, int which) {
372
if (core.authenticatePassword(mPasswordView.getText().toString())) {
373
createUI(savedInstanceState);
374
} else {
375
requestPassword(savedInstanceState);
376
}
377
}
378
});
379
alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.cancel),
380
new DialogInterface.OnClickListener() {
381
382
public void onClick(DialogInterface dialog, int which) {
383
finish();
384
}
385
});
386
alert.show();
387
}
388
389
public void createUI(Bundle savedInstanceState) {
390
if (core == null)
391
return;
392
393
// Now create the UI.
394
// First create the document view
395
mDocView = new MuPDFReaderView(this) {
396
@Override
397
protected void onMoveToChild(int i) {
398
if (core == null)
399
return;
400
mPageNumberView.setText(String.format("%d / %d", i + 1,
401
core.countPages()));
402
mPageSlider.setMax((core.countPages() - 1) * mPageSliderRes);
403
mPageSlider.setProgress(i * mPageSliderRes);
404
super.onMoveToChild(i);
405
}
406
407
@Override
408
protected void onTapMainDocArea() {
409
if (!mButtonsVisible) {
410
showButtons();
411
} else {
412
if (mTopBarMode == TopBarMode.Main)
413
hideButtons();
414
}
415
}
416
417
@Override
418
protected void onDocMotion() {
419
hideButtons();
420
}
421
422
@Override
423
protected void onHit(Hit item) {
424
switch (mTopBarMode) {
425
case Annot:
426
if (item == Hit.Annotation) {
427
showButtons();
428
mTopBarMode = TopBarMode.Delete;
429
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
430
}
431
break;
432
case Delete:
433
mTopBarMode = TopBarMode.Annot;
434
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
435
// fall through
436
default:
437
// Not in annotation editing mode, but the pageview will
438
// still select and highlight hit annotations, so
439
// deselect just in case.
440
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
441
if (pageView != null)
442
pageView.deselectAnnotation();
443
break;
444
}
445
}
446
};
447
mDocView.setAdapter(new MuPDFPageAdapter(this, this, core));
448
449
mSearchTask = new SearchTask(this, core) {
450
@Override
451
protected void onTextFound(SearchTaskResult result) {
452
SearchTaskResult.set(result);
453
// Ask the ReaderView to move to the resulting page
454
mDocView.setDisplayedViewIndex(result.pageNumber);
455
// Make the ReaderView act on the change to SearchTaskResult
456
// via overridden onChildSetup method.
457
mDocView.resetupChildren();
458
}
459
};
460
461
// Make the buttons overlay, and store all its
462
// controls in variables
463
makeButtonsView();
464
465
// Set up the page slider
466
int smax = Math.max(core.countPages()-1,1);
467
mPageSliderRes = ((10 + smax - 1)/smax) * 2;
468
469
// Set the file-name text
470
mFilenameView.setText(mFileName);
471
472
// Activate the seekbar
473
mPageSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
474
public void onStopTrackingTouch(SeekBar seekBar) {
475
mDocView.setDisplayedViewIndex((seekBar.getProgress()+mPageSliderRes/2)/mPageSliderRes);
476
}
477
478
public void onStartTrackingTouch(SeekBar seekBar) {}
479
480
public void onProgressChanged(SeekBar seekBar, int progress,
481
boolean fromUser) {
482
updatePageNumView((progress+mPageSliderRes/2)/mPageSliderRes);
483
}
484
});
485
486
// Activate the search-preparing button
487
mSearchButton.setOnClickListener(new View.OnClickListener() {
488
public void onClick(View v) {
489
searchModeOn();
490
}
491
});
492
493
// Activate the reflow button
494
mReflowButton.setOnClickListener(new View.OnClickListener() {
495
public void onClick(View v) {
496
toggleReflow();
497
}
498
});
499
500
if (core.fileFormat().startsWith("PDF") && core.isUnencryptedPDF() && !core.wasOpenedFromBuffer())
501
{
502
mAnnotButton.setOnClickListener(new View.OnClickListener() {
503
public void onClick(View v) {
504
mTopBarMode = TopBarMode.Annot;
505
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
506
}
507
});
508
}
509
else
510
{
511
mAnnotButton.setVisibility(View.GONE);
512
}
513
514
// Search invoking buttons are disabled while there is no text specified
515
mSearchBack.setEnabled(false);
516
mSearchFwd.setEnabled(false);
517
mSearchBack.setColorFilter(Color.argb(255, 128, 128, 128));
518
mSearchFwd.setColorFilter(Color.argb(255, 128, 128, 128));
519
520
// React to interaction with the text widget
521
mSearchText.addTextChangedListener(new TextWatcher() {
522
523
public void afterTextChanged(Editable s) {
524
boolean haveText = s.toString().length() > 0;
525
setButtonEnabled(mSearchBack, haveText);
526
setButtonEnabled(mSearchFwd, haveText);
527
528
// Remove any previous search results
529
if (SearchTaskResult.get() != null && !mSearchText.getText().toString().equals(SearchTaskResult.get().txt)) {
530
SearchTaskResult.set(null);
531
mDocView.resetupChildren();
532
}
533
}
534
public void beforeTextChanged(CharSequence s, int start, int count,
535
int after) {}
536
public void onTextChanged(CharSequence s, int start, int before,
537
int count) {}
538
});
539
540
//React to Done button on keyboard
541
mSearchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
542
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
543
if (actionId == EditorInfo.IME_ACTION_DONE)
544
search(1);
545
return false;
546
}
547
});
548
549
mSearchText.setOnKeyListener(new View.OnKeyListener() {
550
public boolean onKey(View v, int keyCode, KeyEvent event) {
551
if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER)
552
search(1);
553
return false;
554
}
555
});
556
557
// Activate search invoking buttons
558
mSearchBack.setOnClickListener(new View.OnClickListener() {
559
public void onClick(View v) {
560
search(-1);
561
}
562
});
563
mSearchFwd.setOnClickListener(new View.OnClickListener() {
564
public void onClick(View v) {
565
search(1);
566
}
567
});
568
569
mLinkButton.setOnClickListener(new View.OnClickListener() {
570
public void onClick(View v) {
571
setLinkHighlight(!mLinkHighlight);
572
}
573
});
574
575
if (core.hasOutline()) {
576
mOutlineButton.setOnClickListener(new View.OnClickListener() {
577
public void onClick(View v) {
578
OutlineItem outline[] = core.getOutline();
579
if (outline != null) {
580
OutlineActivityData.get().items = outline;
581
Intent intent = new Intent(MuPDFActivity.this, OutlineActivity.class);
582
startActivityForResult(intent, OUTLINE_REQUEST);
583
}
584
}
585
});
586
} else {
587
mOutlineButton.setVisibility(View.GONE);
588
}
589
590
// Reenstate last state if it was recorded
591
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
592
mDocView.setDisplayedViewIndex(prefs.getInt("page"+mFileName, 0));
593
594
if (savedInstanceState == null || !savedInstanceState.getBoolean("ButtonsHidden", false))
595
showButtons();
596
597
if(savedInstanceState != null && savedInstanceState.getBoolean("SearchMode", false))
598
searchModeOn();
599
600
if(savedInstanceState != null && savedInstanceState.getBoolean("ReflowMode", false))
601
reflowModeSet(true);
602
603
// Stick the document view and the buttons overlay into a parent view
604
RelativeLayout layout = new RelativeLayout(this);
605
layout.addView(mDocView);
606
layout.addView(mButtonsView);
607
setContentView(layout);
608
}
609
610
@Override
611
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
612
switch (requestCode) {
613
case OUTLINE_REQUEST:
614
if (resultCode >= 0)
615
mDocView.setDisplayedViewIndex(resultCode);
616
break;
617
case PRINT_REQUEST:
618
if (resultCode == RESULT_CANCELED)
619
showInfo(getString(R.string.print_failed));
620
break;
621
case FILEPICK_REQUEST:
622
if (mFilePicker != null && resultCode == RESULT_OK)
623
mFilePicker.onPick(data.getData());
624
}
625
super.onActivityResult(requestCode, resultCode, data);
626
}
627
628
public Object onRetainNonConfigurationInstance()
629
{
630
MuPDFCore mycore = core;
631
core = null;
632
return mycore;
633
}
634
635
private void reflowModeSet(boolean reflow)
636
{
637
mReflow = reflow;
638
mDocView.setAdapter(mReflow ? new MuPDFReflowAdapter(this, core) : new MuPDFPageAdapter(this, this, core));
639
mReflowButton.setColorFilter(mReflow ? Color.argb(0xFF, 172, 114, 37) : Color.argb(0xFF, 255, 255, 255));
640
setButtonEnabled(mAnnotButton, !reflow);
641
setButtonEnabled(mSearchButton, !reflow);
642
if (reflow) setLinkHighlight(false);
643
setButtonEnabled(mLinkButton, !reflow);
644
setButtonEnabled(mMoreButton, !reflow);
645
mDocView.refresh(mReflow);
646
}
647
648
private void toggleReflow() {
649
reflowModeSet(!mReflow);
650
showInfo(mReflow ? getString(R.string.entering_reflow_mode) : getString(R.string.leaving_reflow_mode));
651
}
652
653
@Override
654
protected void onSaveInstanceState(Bundle outState) {
655
super.onSaveInstanceState(outState);
656
657
if (mFileName != null && mDocView != null) {
658
outState.putString("FileName", mFileName);
659
660
// Store current page in the prefs against the file name,
661
// so that we can pick it up each time the file is loaded
662
// Other info is needed only for screen-orientation change,
663
// so it can go in the bundle
664
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
665
SharedPreferences.Editor edit = prefs.edit();
666
edit.putInt("page"+mFileName, mDocView.getDisplayedViewIndex());
667
edit.commit();
668
}
669
670
if (!mButtonsVisible)
671
outState.putBoolean("ButtonsHidden", true);
672
673
if (mTopBarMode == TopBarMode.Search)
674
outState.putBoolean("SearchMode", true);
675
676
if (mReflow)
677
outState.putBoolean("ReflowMode", true);
678
}
679
680
@Override
681
protected void onPause() {
682
super.onPause();
683
684
if (mSearchTask != null)
685
mSearchTask.stop();
686
687
if (mFileName != null && mDocView != null) {
688
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
689
SharedPreferences.Editor edit = prefs.edit();
690
edit.putInt("page"+mFileName, mDocView.getDisplayedViewIndex());
691
edit.commit();
692
}
693
}
694
695
public void onDestroy()
696
{
697
if (mDocView != null) {
698
mDocView.applyToChildren(new ReaderView.ViewMapper() {
699
void applyToView(View view) {
700
((MuPDFView)view).releaseBitmaps();
701
}
702
});
703
}
704
if (core != null)
705
core.onDestroy();
706
if (mAlertTask != null) {
707
mAlertTask.cancel(true);
708
mAlertTask = null;
709
}
710
core = null;
711
super.onDestroy();
712
}
713
714
private void setButtonEnabled(ImageButton button, boolean enabled) {
715
button.setEnabled(enabled);
716
button.setColorFilter(enabled ? Color.argb(255, 255, 255, 255):Color.argb(255, 128, 128, 128));
717
}
718
719
private void setLinkHighlight(boolean highlight) {
720
mLinkHighlight = highlight;
721
// LINK_COLOR tint
722
mLinkButton.setColorFilter(highlight ? Color.argb(0xFF, 172, 114, 37) : Color.argb(0xFF, 255, 255, 255));
723
// Inform pages of the change.
724
mDocView.setLinksEnabled(highlight);
725
}
726
727
private void showButtons() {
728
if (core == null)
729
return;
730
if (!mButtonsVisible) {
731
mButtonsVisible = true;
732
// Update page number text and slider
733
int index = mDocView.getDisplayedViewIndex();
734
updatePageNumView(index);
735
mPageSlider.setMax((core.countPages()-1)*mPageSliderRes);
736
mPageSlider.setProgress(index*mPageSliderRes);
737
if (mTopBarMode == TopBarMode.Search) {
738
mSearchText.requestFocus();
739
showKeyboard();
740
}
741
742
Animation anim = new TranslateAnimation(0, 0, -mTopBarSwitcher.getHeight(), 0);
743
anim.setDuration(200);
744
anim.setAnimationListener(new Animation.AnimationListener() {
745
public void onAnimationStart(Animation animation) {
746
mTopBarSwitcher.setVisibility(View.VISIBLE);
747
}
748
public void onAnimationRepeat(Animation animation) {}
749
public void onAnimationEnd(Animation animation) {}
750
});
751
mTopBarSwitcher.startAnimation(anim);
752
753
anim = new TranslateAnimation(0, 0, mPageSlider.getHeight(), 0);
754
anim.setDuration(200);
755
anim.setAnimationListener(new Animation.AnimationListener() {
756
public void onAnimationStart(Animation animation) {
757
mPageSlider.setVisibility(View.VISIBLE);
758
}
759
public void onAnimationRepeat(Animation animation) {}
760
public void onAnimationEnd(Animation animation) {
761
mPageNumberView.setVisibility(View.VISIBLE);
762
}
763
});
764
mPageSlider.startAnimation(anim);
765
}
766
}
767
768
private void hideButtons() {
769
if (mButtonsVisible) {
770
mButtonsVisible = false;
771
hideKeyboard();
772
773
Animation anim = new TranslateAnimation(0, 0, 0, -mTopBarSwitcher.getHeight());
774
anim.setDuration(200);
775
anim.setAnimationListener(new Animation.AnimationListener() {
776
public void onAnimationStart(Animation animation) {}
777
public void onAnimationRepeat(Animation animation) {}
778
public void onAnimationEnd(Animation animation) {
779
mTopBarSwitcher.setVisibility(View.INVISIBLE);
780
}
781
});
782
mTopBarSwitcher.startAnimation(anim);
783
784
anim = new TranslateAnimation(0, 0, 0, mPageSlider.getHeight());
785
anim.setDuration(200);
786
anim.setAnimationListener(new Animation.AnimationListener() {
787
public void onAnimationStart(Animation animation) {
788
mPageNumberView.setVisibility(View.INVISIBLE);
789
}
790
public void onAnimationRepeat(Animation animation) {}
791
public void onAnimationEnd(Animation animation) {
792
mPageSlider.setVisibility(View.INVISIBLE);
793
}
794
});
795
mPageSlider.startAnimation(anim);
796
}
797
}
798
799
private void searchModeOn() {
800
if (mTopBarMode != TopBarMode.Search) {
801
mTopBarMode = TopBarMode.Search;
802
//Focus on EditTextWidget
803
mSearchText.requestFocus();
804
showKeyboard();
805
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
806
}
807
}
808
809
private void searchModeOff() {
810
if (mTopBarMode == TopBarMode.Search) {
811
mTopBarMode = TopBarMode.Main;
812
hideKeyboard();
813
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
814
SearchTaskResult.set(null);
815
// Make the ReaderView act on the change to mSearchTaskResult
816
// via overridden onChildSetup method.
817
mDocView.resetupChildren();
818
}
819
}
820
821
private void updatePageNumView(int index) {
822
if (core == null)
823
return;
824
mPageNumberView.setText(String.format("%d / %d", index+1, core.countPages()));
825
}
826
827
private void printDoc() {
828
if (!core.fileFormat().startsWith("PDF")) {
829
showInfo(getString(R.string.format_currently_not_supported));
830
return;
831
}
832
833
Intent myIntent = getIntent();
834
Uri docUri = myIntent != null ? myIntent.getData() : null;
835
836
if (docUri == null) {
837
showInfo(getString(R.string.print_failed));
838
}
839
840
if (docUri.getScheme() == null)
841
docUri = Uri.parse("file://"+docUri.toString());
842
843
Intent printIntent = new Intent(this, PrintDialogActivity.class);
844
printIntent.setDataAndType(docUri, "aplication/pdf");
845
printIntent.putExtra("title", mFileName);
846
startActivityForResult(printIntent, PRINT_REQUEST);
847
}
848
849
private void showInfo(String message) {
850
mInfoView.setText(message);
851
852
int currentApiVersion = android.os.Build.VERSION.SDK_INT;
853
if (currentApiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
854
SafeAnimatorInflater safe = new SafeAnimatorInflater((Activity)this, R.animator.info, (View)mInfoView);
855
} else {
856
mInfoView.setVisibility(View.VISIBLE);
857
mHandler.postDelayed(new Runnable() {
858
public void run() {
859
mInfoView.setVisibility(View.INVISIBLE);
860
}
861
}, 500);
862
}
863
}
864
865
private void makeButtonsView() {
866
mButtonsView = getLayoutInflater().inflate(R.layout.buttons,null);
867
mFilenameView = (TextView)mButtonsView.findViewById(R.id.docNameText);
868
mPageSlider = (SeekBar)mButtonsView.findViewById(R.id.pageSlider);
869
mPageNumberView = (TextView)mButtonsView.findViewById(R.id.pageNumber);
870
mInfoView = (TextView)mButtonsView.findViewById(R.id.info);
871
mSearchButton = (ImageButton)mButtonsView.findViewById(R.id.searchButton);
872
mReflowButton = (ImageButton)mButtonsView.findViewById(R.id.reflowButton);
873
mOutlineButton = (ImageButton)mButtonsView.findViewById(R.id.outlineButton);
874
mAnnotButton = (ImageButton)mButtonsView.findViewById(R.id.editAnnotButton);
875
mAnnotTypeText = (TextView)mButtonsView.findViewById(R.id.annotType);
876
mTopBarSwitcher = (ViewAnimator)mButtonsView.findViewById(R.id.switcher);
877
mSearchBack = (ImageButton)mButtonsView.findViewById(R.id.searchBack);
878
mSearchFwd = (ImageButton)mButtonsView.findViewById(R.id.searchForward);
879
mSearchText = (EditText)mButtonsView.findViewById(R.id.searchText);
880
mLinkButton = (ImageButton)mButtonsView.findViewById(R.id.linkButton);
881
mMoreButton = (ImageButton)mButtonsView.findViewById(R.id.moreButton);
882
mTopBarSwitcher.setVisibility(View.INVISIBLE);
883
mPageNumberView.setVisibility(View.INVISIBLE);
884
mInfoView.setVisibility(View.INVISIBLE);
885
mPageSlider.setVisibility(View.INVISIBLE);
886
}
887
888
public void OnMoreButtonClick(View v) {
889
mTopBarMode = TopBarMode.More;
890
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
891
}
892
893
public void OnCancelMoreButtonClick(View v) {
894
mTopBarMode = TopBarMode.Main;
895
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
896
}
897
898
public void OnPrintButtonClick(View v) {
899
printDoc();
900
}
901
902
public void OnCopyTextButtonClick(View v) {
903
mTopBarMode = TopBarMode.Accept;
904
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
905
mAcceptMode = AcceptMode.CopyText;
906
mDocView.setMode(MuPDFReaderView.Mode.Selecting);
907
mAnnotTypeText.setText(getString(R.string.copy_text));
908
showInfo(getString(R.string.select_text));
909
}
910
911
public void OnEditAnnotButtonClick(View v) {
912
mTopBarMode = TopBarMode.Annot;
913
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
914
}
915
916
public void OnCancelAnnotButtonClick(View v) {
917
mTopBarMode = TopBarMode.More;
918
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
919
}
920
921
public void OnHighlightButtonClick(View v) {
922
mTopBarMode = TopBarMode.Accept;
923
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
924
mAcceptMode = AcceptMode.Highlight;
925
mDocView.setMode(MuPDFReaderView.Mode.Selecting);
926
mAnnotTypeText.setText(R.string.highlight);
927
showInfo(getString(R.string.select_text));
928
}
929
930
public void OnUnderlineButtonClick(View v) {
931
mTopBarMode = TopBarMode.Accept;
932
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
933
mAcceptMode = AcceptMode.Underline;
934
mDocView.setMode(MuPDFReaderView.Mode.Selecting);
935
mAnnotTypeText.setText(R.string.underline);
936
showInfo(getString(R.string.select_text));
937
}
938
939
public void OnStrikeOutButtonClick(View v) {
940
mTopBarMode = TopBarMode.Accept;
941
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
942
mAcceptMode = AcceptMode.StrikeOut;
943
mDocView.setMode(MuPDFReaderView.Mode.Selecting);
944
mAnnotTypeText.setText(R.string.strike_out);
945
showInfo(getString(R.string.select_text));
946
}
947
948
public void OnInkButtonClick(View v) {
949
mTopBarMode = TopBarMode.Accept;
950
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
951
mAcceptMode = AcceptMode.Ink;
952
mDocView.setMode(MuPDFReaderView.Mode.Drawing);
953
mAnnotTypeText.setText(R.string.ink);
954
showInfo(getString(R.string.draw_annotation));
955
}
956
957
public void OnCancelAcceptButtonClick(View v) {
958
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
959
if (pageView != null) {
960
pageView.deselectText();
961
pageView.cancelDraw();
962
}
963
mDocView.setMode(MuPDFReaderView.Mode.Viewing);
964
switch (mAcceptMode) {
965
case CopyText:
966
mTopBarMode = TopBarMode.More;
967
break;
968
default:
969
mTopBarMode = TopBarMode.Annot;
970
break;
971
}
972
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
973
}
974
975
public void OnAcceptButtonClick(View v) {
976
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
977
boolean success = false;
978
switch (mAcceptMode) {
979
case CopyText:
980
if (pageView != null)
981
success = pageView.copySelection();
982
mTopBarMode = TopBarMode.More;
983
showInfo(success?getString(R.string.copied_to_clipboard):getString(R.string.no_text_selected));
984
break;
985
986
case Highlight:
987
if (pageView != null)
988
success = pageView.markupSelection(Annotation.Type.HIGHLIGHT);
989
mTopBarMode = TopBarMode.Annot;
990
if (!success)
991
showInfo(getString(R.string.no_text_selected));
992
break;
993
994
case Underline:
995
if (pageView != null)
996
success = pageView.markupSelection(Annotation.Type.UNDERLINE);
997
mTopBarMode = TopBarMode.Annot;
998
if (!success)
999
showInfo(getString(R.string.no_text_selected));
1000
break;
1001
1002
case StrikeOut:
1003
if (pageView != null)
1004
success = pageView.markupSelection(Annotation.Type.STRIKEOUT);
1005
mTopBarMode = TopBarMode.Annot;
1006
if (!success)
1007
showInfo(getString(R.string.no_text_selected));
1008
break;
1009
1010
case Ink:
1011
if (pageView != null)
1012
success = pageView.saveDraw();
1013
mTopBarMode = TopBarMode.Annot;
1014
if (!success)
1015
showInfo(getString(R.string.nothing_to_save));
1016
break;
1017
}
1018
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
1019
mDocView.setMode(MuPDFReaderView.Mode.Viewing);
1020
}
1021
1022
public void OnCancelSearchButtonClick(View v) {
1023
searchModeOff();
1024
}
1025
1026
public void OnDeleteButtonClick(View v) {
1027
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
1028
if (pageView != null)
1029
pageView.deleteSelectedAnnotation();
1030
mTopBarMode = TopBarMode.Annot;
1031
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
1032
}
1033
1034
public void OnCancelDeleteButtonClick(View v) {
1035
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
1036
if (pageView != null)
1037
pageView.deselectAnnotation();
1038
mTopBarMode = TopBarMode.Annot;
1039
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
1040
}
1041
1042
private void showKeyboard() {
1043
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
1044
if (imm != null)
1045
imm.showSoftInput(mSearchText, 0);
1046
}
1047
1048
private void hideKeyboard() {
1049
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
1050
if (imm != null)
1051
imm.hideSoftInputFromWindow(mSearchText.getWindowToken(), 0);
1052
}
1053
1054
private void search(int direction) {
1055
hideKeyboard();
1056
int displayPage = mDocView.getDisplayedViewIndex();
1057
SearchTaskResult r = SearchTaskResult.get();
1058
int searchPage = r != null ? r.pageNumber : -1;
1059
mSearchTask.go(mSearchText.getText().toString(), direction, displayPage, searchPage);
1060
}
1061
1062
@Override
1063
public boolean onSearchRequested() {
1064
if (mButtonsVisible && mTopBarMode == TopBarMode.Search) {
1065
hideButtons();
1066
} else {
1067
showButtons();
1068
searchModeOn();
1069
}
1070
return super.onSearchRequested();
1071
}
1072
1073
@Override
1074
public boolean onPrepareOptionsMenu(Menu menu) {
1075
if (mButtonsVisible && mTopBarMode != TopBarMode.Search) {
1076
hideButtons();
1077
} else {
1078
showButtons();
1079
searchModeOff();
1080
}
1081
return super.onPrepareOptionsMenu(menu);
1082
}
1083
1084
@Override
1085
protected void onStart() {
1086
if (core != null)
1087
{
1088
core.startAlerts();
1089
createAlertWaiter();
1090
}
1091
1092
super.onStart();
1093
}
1094
1095
@Override
1096
protected void onStop() {
1097
if (core != null)
1098
{
1099
destroyAlertWaiter();
1100
core.stopAlerts();
1101
}
1102
1103
super.onStop();
1104
}
1105
1106
@Override
1107
public void onBackPressed() {
1108
if (core != null && core.hasChanges()) {
1109
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
1110
public void onClick(DialogInterface dialog, int which) {
1111
if (which == AlertDialog.BUTTON_POSITIVE)
1112
core.save();
1113
1114
finish();
1115
}
1116
};
1117
AlertDialog alert = mAlertBuilder.create();
1118
alert.setTitle("MuPDF");
1119
alert.setMessage(getString(R.string.document_has_changes_save_them_));
1120
alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.yes), listener);
1121
alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.no), listener);
1122
alert.show();
1123
} else {
1124
super.onBackPressed();
1125
}
1126
}
1127
1128
@Override
1129
public void performPickFor(FilePicker picker) {
1130
mFilePicker = picker;
1131
Intent intent = new Intent(this, ChoosePDFActivity.class);
1132
intent.setAction(ChoosePDFActivity.PICK_KEY_FILE);
1133
startActivityForResult(intent, FILEPICK_REQUEST);
1134
}
1135
}
1136
1137