Added own crash handler for debugging
[DHBWCampusApp.git] / app / src / main / java / de / dhbwloe / campusapp / CampusApp.java
1 /* CampusApp.java
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 package de.dhbwloe.campusapp;
17
18 import android.content.Context;
19 import android.content.Intent;
20 import android.content.res.TypedArray;
21 import android.nfc.NfcAdapter;
22 import android.os.Bundle;
23 import android.support.design.widget.FloatingActionButton;
24 import android.support.design.widget.Snackbar;
25 import android.support.v4.app.FragmentActivity;
26 import android.util.Log;
27 import android.view.KeyEvent;
28 import android.view.View;
29 import android.support.design.widget.NavigationView;
30 import android.support.v4.view.GravityCompat;
31 import android.support.v4.widget.DrawerLayout;
32 import android.support.v7.app.ActionBarDrawerToggle;
33 import android.support.v7.app.AppCompatActivity;
34 import android.support.v7.widget.Toolbar;
35 import android.view.Menu;
36 import android.view.MenuItem;
37 import android.view.inputmethod.EditorInfo;
38 import android.view.inputmethod.InputMethodManager;
39 import android.widget.EditText;
40 import android.widget.ImageView;
41 import android.widget.LinearLayout;
42 import android.widget.TextView;
43
44 import java.util.Date;
45
46 import de.dhbwloe.campusapp.nfcreader.NfcCardListener;
47
48 public class CampusApp extends FragmentActivity {
49     private boolean bSearchActive = false;
50     private CampusAppContext AppContext = null;
51
52     /*
53     * Dev Info:
54     *
55     * Die App besteht aus einer einzigen Activity, auf welcher dynamisch Fragmente platziert werden.
56     * Das Menü, sowie die Headerleiste befinden sich auf der Activity, sind dementsprechend immer verfügbar.
57     *
58     * Zur laufzeit der App wird eine einzige Instanz der Klasse CampusAppContext angelegt.
59     * Dieser Kontext dient als einstiegspunkt für sämmtliche global verfügbaren verwaltungs tools.
60     * Dazu gehören:
61     *   AppContext.getNavigationManager()    NavigationManager   Verwaltet die angezeigten Fragmente und deren Navigation
62     *                                                            .navigatePage("Dashboard")  to navigate to the Dashboard
63     *   ... to be continued ...
64      */
65
66     @Override
67     protected void onCreate(Bundle savedInstanceState) {
68         Log.i("CampusApp", "Event: onCreate");
69
70         if(CampusAppContext.DEBUG) {
71             final Thread.UncaughtExceptionHandler systemExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
72             final CampusAppExceptionHandler oExceptionHandler = new CampusAppExceptionHandler();
73             Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler() {
74                 @Override
75                 public void uncaughtException(Thread thread, Throwable e) {
76                     oExceptionHandler.handleUncaughtException(thread, e);
77                     //systemExceptionHandler.uncaughtException(thread, e);
78                     System.exit(1);
79                 }
80             });
81         }
82
83         super.onCreate(savedInstanceState);
84         setContentView(R.layout.activity_campus_app);
85
86         // Erstelle neuen AppContext, wenn keiner existiert
87         AppContext = CampusAppContext.getInstance();
88         if(AppContext == null)
89             AppContext = new CampusAppContext(this, R.id.fragment_container, R.id.nav_view);
90         else
91             AppContext.setMainActivity(this);
92
93         // Wenn die App aus dem Ruhezustand (oder auch Orientation change) reaktiviert wird soll nicht zuerst der Splashscreen angezeigt werden.
94         boolean instantRestore = false;
95         if(savedInstanceState != null) {
96             long lastrun = savedInstanceState.getLong("lastrun");
97             lastrun = ((new Date()).getTime()/1000) - lastrun;
98             Log.i("CampusApp", "Restored from Idle state! Idled: "+lastrun+" secs");
99             if(lastrun < 30) {
100                 instantRestore = true;
101
102                 // restore previous Title
103                 AppContext.setTitle(savedInstanceState.getString("activetitle"));
104             }
105
106
107             Bundle contextVars = savedInstanceState.getBundle("savedContextVariables");
108             if(contextVars != null) {
109                 Bundle contextVariables = AppContext.getContextVariables();
110                 contextVariables.putAll(contextVars);
111             }
112         }
113
114         prepareMainUi();
115         if(instantRestore) // orientation change
116             loadMainUi();
117         else
118             // don't add navigation to SlashScreen, or even from SplashScreen to Dashboard to the history log!
119             // it would be very strange to return to the SplashScreen or an "empty" page on return ;)
120             AppContext.getNavigationManager().navigatePage("SplashScreen", null, false);
121
122     }
123
124     @Override
125     public void onSaveInstanceState(Bundle savedInstanceState) {
126         Log.i("CampusApp", "Event: onSaveInstanceState");
127
128         // Save instance state during "restarts" due to orientation changes.
129         // We don't want to see the splash screen everytime the orientation changes ;)
130         savedInstanceState.putLong("lastrun", (new Date()).getTime() / 1000);
131         savedInstanceState.putString("activepage", AppContext.getNavigationManager().getCurrentPageName());
132         TextView titleView = (TextView) findViewById(R.id.title);
133         savedInstanceState.putString("activetitle", titleView.getText().toString());
134
135         Bundle contextVariables = AppContext.getContextVariables();
136         savedInstanceState.putBundle("savedContextVariables", contextVariables);
137
138         // Always call the superclass so it can save the view hierarchy state
139         super.onSaveInstanceState(savedInstanceState);
140     }
141
142     public void prepareMainUi() {
143         ImageView btnOpenSearch = (ImageView) findViewById(R.id.search_button);
144         btnOpenSearch.setVisibility(View.GONE);
145     }
146
147     public void loadMainUi() {
148         ImageView btnOpenSearch = (ImageView) findViewById(R.id.search_button);
149
150         btnOpenSearch.setVisibility(View.VISIBLE);
151         setupActionBar();
152         setupSearchTriggers();
153
154         AppContext.getNfcCardListener().startNfcListener();
155     }
156
157     private void setupActionBar() {
158         Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
159         DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
160         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
161         drawer.setDrawerListener(toggle);
162         toggle.syncState();
163
164         NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
165         navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
166             @SuppressWarnings("StatementWithEmptyBody")
167             @Override
168             public boolean onNavigationItemSelected(MenuItem item) {
169                 // Handle navigation view item clicks here.
170                 int id = item.getItemId();
171
172                 for(CampusAppContext.NavigationItem navitem : AppContext.NAVIGATION_TARGETS) {
173                     if(navitem.navItemId == id) {
174                         AppContext.getNavigationManager().navigatePage(navitem.navTarget);
175                         break;
176                     }
177                 }
178
179                 DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
180                 drawer.closeDrawer(GravityCompat.START);
181                 return true;
182             }
183         });
184     }
185
186     private void setupSearchTriggers() {
187         ImageView btnOpenSearch = (ImageView) findViewById(R.id.search_button);
188         ImageView btnCloseSearch = (ImageView) findViewById(R.id.search_clear);
189         EditText edtSearchInput = (EditText) findViewById(R.id.search_input);
190         TextView txtTitle = (TextView) findViewById(R.id.title);
191
192         // EventListener für Suchfunktion
193         btnOpenSearch.setOnClickListener(new View.OnClickListener() {
194             @Override
195             public void onClick(View view) {
196                 triggerSearchPanel(true);
197             }
198         });
199         edtSearchInput.setOnFocusChangeListener(new View.OnFocusChangeListener() {
200             @Override
201             public void onFocusChange(View v, boolean hasFocus) {
202                 EditText edtSearchInput = (EditText) v;
203                 if (!hasFocus && edtSearchInput.getText().length() == 0) {
204                     triggerSearchPanel(false);
205                 }
206             }
207         });
208         edtSearchInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
209             @Override
210             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
211                 if (actionId == EditorInfo.IME_ACTION_SEARCH) {
212                     EditText edtSearchInput = (EditText) v;
213                     triggerSearchAction(edtSearchInput.getText().toString());
214                     triggerSearchPanel(false);
215                     return true;
216                 }
217                 return false;
218             }
219         });
220         btnCloseSearch.setOnClickListener(new View.OnClickListener() {
221             @Override
222             public void onClick(View view) {
223                 EditText edtSearchInput = (EditText) findViewById(R.id.search_input);
224                 edtSearchInput.setText("");
225                 triggerSearchPanel(false);
226             }
227         });
228         txtTitle.setOnClickListener(new View.OnClickListener() {
229             @Override
230             public void onClick(View view) {
231                 triggerSearchPanel(true);
232             }
233         });
234
235     }
236
237     private void triggerSearchPanel(boolean show) {
238         if(bSearchActive == show)
239             return;
240         bSearchActive = show;
241         LinearLayout layTitleContainer = (LinearLayout) findViewById(R.id.title_container);
242         LinearLayout laySearchContainer = (LinearLayout) findViewById(R.id.search_container);
243         EditText edtSearchInput = (EditText) findViewById(R.id.search_input);
244
245         InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
246         if(show) {
247             layTitleContainer.setVisibility(View.GONE);
248             laySearchContainer.setVisibility(View.VISIBLE);
249             edtSearchInput.requestFocus();
250
251             imm.showSoftInput(edtSearchInput, InputMethodManager.SHOW_IMPLICIT);
252         } else {
253             layTitleContainer.setVisibility(View.VISIBLE);
254             laySearchContainer.setVisibility(View.GONE);
255
256             View view = this.getCurrentFocus();
257             if (view != null) {
258                 imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
259             }
260         }
261     }
262
263     private void triggerSearchAction(String query) {
264         Bundle bundle = new Bundle();
265         bundle.putString("query", query);
266
267         AppContext.getNavigationManager().navigatePage("AppSearch", bundle);
268     }
269
270     @Override
271     public void onBackPressed() {
272         DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
273         if (drawer.isDrawerOpen(GravityCompat.START)) {
274             drawer.closeDrawer(GravityCompat.START);
275         } else if(!AppContext.getNavigationManager().back()) {
276             super.onBackPressed(); // trigger system action if internal navigation manager returns false for back()
277         }
278     }
279
280     @Override
281     public boolean onCreateOptionsMenu(Menu menu) {
282         // Inflate the menu; this adds items to the action bar if it is present.
283         getMenuInflater().inflate(R.menu.campus_app, menu);
284         return true;
285     }
286
287     @Override
288     public boolean onOptionsItemSelected(MenuItem item) {
289         // Handle action bar item clicks here. The action bar will
290         // automatically handle clicks on the Home/Up button, so long
291         // as you specify a parent activity in AndroidManifest.xml.
292         int id = item.getItemId();
293
294         //noinspection SimplifiableIfStatement
295         if (id == R.id.action_settings) {
296             return true;
297         }
298
299         return super.onOptionsItemSelected(item);
300     }
301
302     /* nfc listener related callbacks */
303     @Override
304     public void onResume() {
305         if(AppContext == null)
306             AppContext = CampusAppContext.getInstance();
307         if(AppContext == null)
308             AppContext = new CampusAppContext(this, R.id.fragment_container, R.id.nav_view);
309         else
310             AppContext.setMainActivity(this);
311         
312         super.onResume();
313         Log.i("CampusApp", "onResume event");
314         AppContext.getNfcCardListener().resumeForefrontDispatcher();
315     }
316
317     @Override
318     public void onPause() {
319         super.onPause();
320         Log.i("CampusApp", "Event: onPause");
321         AppContext.getNfcCardListener().pauseForefrontDispatcher();
322     }
323
324     @Override
325     public void onNewIntent(Intent intent) {
326         if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
327             AppContext.getNfcCardListener().handleNfcEvent(intent);
328         }
329     }
330
331 }