App

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

AppMainActivity.java
Go to the documentation of this file.
1 package mhr.app;
2
3 import java.io.BufferedWriter;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.OutputStream;
9 import java.io.OutputStreamWriter;
10 import java.io.PrintWriter;
11 import java.io.StringWriter;
12
13 import javax.xml.transform.TransformerException;
14 import javax.xml.transform.stream.StreamResult;
15
16 import mhr.app.fragments.layers.LayersPaneFragment;
17 import mhr.app.fragments.toolbox.ToolBoxPaneFragment;
18 import mhr.appandroid.adapters.APDBitmap;
19 import mhr.appandroid.displayer.BitmapDisplayer;
20 import mhr.appcore.AppCore;
21 import mhr.appcore.commands.AppCommand;
22 import mhr.appcore.interfaces.PDExceptionFeedback;
23 import mhr.app.R;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.provider.MediaStore;
27 import android.app.Activity;
28 import android.app.AlertDialog;
29 import android.app.Fragment;
30 import android.app.FragmentTransaction;
31 import android.content.DialogInterface;
32 import android.content.Intent;
33 import android.database.Cursor;
34 import android.graphics.Bitmap;
35 import android.graphics.BitmapFactory;
36 import android.graphics.Canvas;
37 import android.util.Log;
38 import android.view.SurfaceView;
39 import android.view.View;
40 import android.view.View.OnTouchListener;
41 import android.widget.FrameLayout;
42 import android.widget.TextView;
43 import android.widget.Toast;
44
49 public class AppMainActivity extends Activity {
50
51 static {
52 System.loadLibrary("gnustl_shared");
53 System.loadLibrary("app_android");
54 System.loadLibrary("app_core");
55 }
56
57 //===== INTERFACES, CLASSES, ENUMS ==========================================================================================================//
58 //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
62 protected class ExceptionFeedback implements PDExceptionFeedback {
63
64 @Override
65 public void feedback(final Exception e) {
66 AppMainActivity.this.runOnUiThread(new Runnable() {
67
68 @Override
69 public void run() {
70 AppMainActivity.this.onExceptionFeedback(e);
71
72 }
73 });
74
75 }
76
77 }
78
79
83 protected class UnblockException implements DialogInterface.OnClickListener {
84
85 @Override
86 public void onClick(DialogInterface dialog, int which) {
87 AppMainActivity.this.app.unsetExceptionFlag();
88 AppMainActivity.this.hideProgressBar();
89
90 }
91
92 }
93
97 protected class WorkerEH implements Thread.UncaughtExceptionHandler {
98
99 @Override
100 public void uncaughtException(Thread thread, Throwable ex) {
101 final Throwable threx = ex;
102 runOnUiThread(new Runnable() {
103 @Override
104 public void run() {
105 AlertDialog.Builder b = new AlertDialog.Builder(AppMainActivity.this);
106 final Throwable thr = threx;
107 b.setTitle("Worker unhandled exception!");
108
109 // StringWriter sw = new StringWriter();
110 // PrintWriter pw = new PrintWriter(sw);
111 // thr.printStackTrace(pw);
112 // b.setMessage(threx.toString() + "\n\n" + sw.toString());
113
114 b.setMessage(threx.getMessage());
115 b.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
116 @Override
117 public void onClick(DialogInterface dialog, int which) {
118 thr.printStackTrace();
119 finish();
120 }
121 });
122 b.create().show();
123 }
124 });
125 }
126
127 }
128
132 protected class RendererEH implements Thread.UncaughtExceptionHandler {
133
134 @Override
135 public void uncaughtException(Thread thread, Throwable ex) {
136 final Throwable threx = ex;
137 runOnUiThread(new Runnable() {
138 @Override
139 public void run() {
140 AlertDialog.Builder b = new AlertDialog.Builder(AppMainActivity.this);
141 final Throwable thr = threx;
142 b.setTitle("Renderer unhandled exception!");
143
144 // StringWriter sw = new StringWriter();
145 // PrintWriter pw = new PrintWriter(sw);
146 // thr.printStackTrace(pw);
147 // b.setMessage(threx.toString() + "\n\n" + sw.toString());
148 b.setMessage(threx.getMessage());
149 b.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
150 @Override
151 public void onClick(DialogInterface dialog, int which) {
152 thr.printStackTrace();
153 finish();
154 }
155 });
156 b.create().show();
157 }
158 });
159 }
160
161 }
162
166 protected class UIEH implements Thread.UncaughtExceptionHandler {
167
168 @Override
169 public void uncaughtException(Thread thread, Throwable ex) {
170 File root = getExternalFilesDir(null);
171 File err = new File(root, "err.txt");
172 OutputStream output = null;
173 StringWriter sw = new StringWriter();
174 PrintWriter pw = new PrintWriter(sw);
175 ex.printStackTrace(pw);
176 BufferedWriter writer = null;
177 try {
178 output = new FileOutputStream(err);
179 writer = new BufferedWriter(new OutputStreamWriter(output));
180 writer.append(sw.toString());
181 writer.flush();
182 } catch (Exception e) {
183 e.printStackTrace();
184 throw new RuntimeException("Unhandled exception " + e.toString());
185 } finally {
186 if (writer != null) {
187 try {
188 writer.close();
189 } catch (IOException e) {
190 throw new RuntimeException("Unhandled exception " + e.toString());
191 }
192 }
193 if (output != null) {
194 try {
195 output.close();
196 } catch (IOException e) {
197 throw new RuntimeException("Unhandled exception " + e.toString());
198 }
199 }
200 }
201 ex.printStackTrace();
202 finish();
203 }
204 }
205
206 //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
207
208 //===== FIELDS ==============================================================================================================================//
209 //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
210 protected BitmapDisplayer disp;
211 protected AppCore app;
212
213 protected ToolBoxPaneFragment toolBoxPane;
214 protected LayersPaneFragment layersPane;
215 protected Fragment dialog;
216 protected View dialogPlaceholder;
217 protected View progressBarOverlay;
218 protected SurfaceView canvas;
219 protected FrameLayout guiOverCanvas;
220
221 protected boolean invalidScreen = false;
222
223 //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
224 public static final int OPEN_IMAGE_FROM_GALLERY_REQUEST_CODE = 1001;
225
226 //===== CONSTRUCTORS, DESTRUCTORS, RELATED METHODS ==========================================================================================//
227 //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
228 //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
229
230 //===== METHODS =============================================================================================================================//
231 //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
232 //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
233
238 public LayersPaneFragment getLayersPane() {
239 return layersPane;
240 }
241
246 public BitmapDisplayer getBitmapDisplayer() {
247 return disp;
248 }
249
254 public AppCore getAppCore() {
255 return app;
256 }
257
262 public void addCommand(AppCommand cmd) {
263 app.addCommand(cmd);
264 }
265
270 public void setCanvasOnTouchListener(OnTouchListener listener) {
271 canvas.setOnTouchListener(listener);
272 }
273
278 public void showDialog(Fragment dialog) {
279 dismissDialog();
280 this.dialog = dialog;
281 dialogPlaceholder.setVisibility(View.VISIBLE);
282 getFragmentManager().beginTransaction().replace(R.id.DialogPlaceholder, dialog).commit();
283 }
284
288 public void dismissDialog() {
289 if (dialog != null) {
290 getFragmentManager().beginTransaction().remove(dialog).commit();
291 dialogPlaceholder.setVisibility(View.GONE);
292 dialog = null;
293 }
294 }
295
299 public void showProgressBar() {
300 progressBarOverlay.setVisibility(View.VISIBLE);
301 }
302
306 public void hideProgressBar() {
307 progressBarOverlay.setVisibility(View.GONE);
308 }
309
314 public FrameLayout getGuiOverCanvas() {
315 return guiOverCanvas;
316 }
317
322 public void onExceptionFeedback(Exception e) {
323 AlertDialog.Builder builder = new AlertDialog.Builder(this);
324 builder.setTitle("Non-fatal exception occured")
325 .setIconAttribute(android.R.attr.alertDialogIcon)
326 .setMessage(e.getMessage())
327 .setCancelable(false)
328 .setPositiveButton("Continue", new UnblockException());
329 AlertDialog alert = builder.create();
330 alert.show();
331 }
332
338 public String getPath(Uri uri) {
339 String[] projection = { MediaStore.Images.Media.DATA };
340 Cursor cursor = managedQuery(uri, projection, null, null, null);
341 int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
342 cursor.moveToFirst();
343 return cursor.getString(column_index);
344 }
345
346 //===== CALLBACKS ===========================================================================================================================//
347 @Override
348 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
349 String filePath = null;
350 String realPath = null;
351 File imgFile = null;
352 switch (requestCode) {
353 case OPEN_IMAGE_FROM_GALLERY_REQUEST_CODE:
354 if (resultCode == RESULT_OK && data != null && data.getData() != null) {
355 filePath = data.getData().getPath();
356 imgFile = new File(filePath);
357 if (!imgFile.exists()) {
358 realPath = this.getPath(data.getData()); // TOTO je správný postup, ale některé programy jako Astro jej nedodržují a vrací reálnou cestu
359 imgFile = new File(realPath);
360 }
361 if (imgFile.exists()) {
362 Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
363 app.openImage(new APDBitmap(myBitmap));
364 layersPane.reseImagePresentation();
365 }
366 }
367 }
368 }
369
370 @Override
371 public void onBackPressed() {
372 AlertDialog.Builder b = new AlertDialog.Builder(this);
373 b.setTitle("Exit").setMessage("Dou you really want to exit?");
374 b.setNegativeButton("No", null);
375 b.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
376
377 @Override
378 public void onClick(DialogInterface dialog, int which) {
379 AppMainActivity.this.finish();
380
381 }
382 });
383 b.create().show();
384 }
385
386 //----- LIFE CYCLE --------------------------------------------------------------------------------------------------------------------------//
387
388 @Override
389 protected void onCreate(Bundle savedInstanceState) {
390 super.onCreate(savedInstanceState);
391 /*
392 * Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc.
393 * This method also provides you with a Bundle containing the activity's previously frozen state, if there was one. Always followed by onStart().
394 *
395 * NOT KILLABlE
396 */
397 setContentView(R.layout.activity_app_main);
398
399 if (findViewById(R.id.ErrorMessage) != null) {
400 AlertDialog.Builder b = new AlertDialog.Builder(this);
401 b.setTitle("ERROR").setMessage("Only 10'' screens are currently supported.");
402 b.setCancelable(false);
403 b.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
404
405 @Override
406 public void onClick(DialogInterface dialog, int which) {
407 AppMainActivity.this.finish();
408
409 }
410 });
411 b.create().show();
412 invalidScreen = true;
413 return;
414 }
415
416 Thread.setDefaultUncaughtExceptionHandler(new UIEH());
417
418 dialogPlaceholder = findViewById(R.id.DialogPlaceholder);
419 progressBarOverlay = findViewById(R.id.ProgressBarOverlay);
420 guiOverCanvas = (FrameLayout) findViewById(R.id.GuiOverCanvasPlaceholder);
421
422 canvas = (SurfaceView) findViewById(R.id.DrawingCanvas);
423 disp = new BitmapDisplayer(canvas);
424
425 toolBoxPane = new ToolBoxPaneFragment();
426 layersPane = new LayersPaneFragment();
427 FragmentTransaction ft = getFragmentManager().beginTransaction();
428 ft.replace(R.id.LeftStrip, toolBoxPane);
429 ft.replace(R.id.RightStrip, layersPane);
430 ft.commit();
431
432 app = new AppCore(disp);
433 app.setExceptionFeedback(new ExceptionFeedback());
434
435 Bitmap initBitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
436 Canvas canv = new Canvas(initBitmap);
437 canv.drawColor(0xFFFFFFFF);
438 app.openImage(new APDBitmap(initBitmap));
439
440 app.setWorkingThreadEH(new WorkerEH());
441 app.setRenderingThreadEH(new RendererEH());
442
443 }
444
445 @Override
446 protected void onRestart() {
447 super.onRestart();
448 if (invalidScreen) {
449 return;
450 }
451 /*
452 * Called after your activity has been stopped, prior to it being started again. Always followed by onStart()
453 *
454 * NOT KILLABLE
455 */
456 }
457
458 @Override
459 protected void onStart() {
460 super.onStart();
461 if (invalidScreen) {
462 return;
463 }
464 /*
465 * Called when the activity is becoming visible to the user. Followed by onResume() if the activity comes to the foreground,
466 * or onStop() if it becomes hidden.
467 *
468 * NOT KILLABLE
469 */
470 app.setImagePresentation(layersPane.getImagePresentation());
471 }
472
473 @Override
474 protected void onResume() {
475 super.onResume();
476 if (invalidScreen) {
477 return;
478 }
479
480 disp.centerAndResetZoom();
481 /*
482 * Called when the activity will start interacting with the user. At this point your activity is at the top of the activity stack,
483 * with user input going to it. Always followed by onPause().
484 *
485 * NOT KILLABLE
486 */
487 // layersPane.updateLayers();
488
489 }
490
491 @Override
492 protected void onPause() {
493 super.onPause();
494 if (invalidScreen) {
495 return;
496 }
497
498 /*
499 * Called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data,
500 * stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity
501 * will not be resumed until this method returns. Followed by either onResume() if the activity returns back to the front, or onStop() if it
502 * becomes invisible to the user.
503 *
504 * NOT KILLABLE
505 */
506 }
507
508 @Override
509 protected void onStop() {
510 super.onStop();
511 if (invalidScreen) {
512 return;
513 }
514
515 /*
516 * Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen
517 * either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed. Followed
518 * by either onRestart() if this activity is coming back to interact with the user, or onDestroy() if this activity is going away.
519 *
520 * KILLABLE
521 */
522 }
523
524 @Override
525 protected void onDestroy() {
526 super.onDestroy();
527 if (invalidScreen) {
528 return;
529 }
530
531 app.dispose();
532 /*
533 * The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it,
534 * or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the
535 * isFinishing() method.
536 *
537 * KILLABLE
538 */
539 }
540 }