App
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() {
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) {
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 --------------------------------------------------------------------------------------------------------------------------//
211  protected AppCore app;
212 
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 
239  return layersPane;
240  }
241 
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) {
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));
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 
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);
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 
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  */
471  }
472 
473  @Override
474  protected void onResume() {
475  super.onResume();
476  if (invalidScreen) {
477  return;
478  }
479 
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 }