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.
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.
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/>.
16 package de.dhbwloe.campusapp;
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;
44 import java.util.Date;
46 import de.dhbwloe.campusapp.nfcreader.NfcCardListener;
48 public class CampusApp extends FragmentActivity {
49 private boolean bSearchActive = false;
50 private CampusAppContext AppContext = null;
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.
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.
61 * AppContext.getNavigationManager() NavigationManager Verwaltet die angezeigten Fragmente und deren Navigation
62 * .navigatePage("Dashboard") to navigate to the Dashboard
63 * ... to be continued ...
67 protected void onCreate(Bundle savedInstanceState) {
68 Log.i("CampusApp", "Event: onCreate");
70 if(CampusAppContext.DEBUG) {
71 final Thread.UncaughtExceptionHandler systemExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
72 final CampusAppExceptionHandler oExceptionHandler = new CampusAppExceptionHandler();
73 Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler() {
75 public void uncaughtException(Thread thread, Throwable e) {
76 oExceptionHandler.handleUncaughtException(thread, e);
77 //systemExceptionHandler.uncaughtException(thread, e);
83 super.onCreate(savedInstanceState);
84 setContentView(R.layout.activity_campus_app);
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);
91 AppContext.setMainActivity(this);
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");
100 instantRestore = true;
102 // restore previous Title
103 AppContext.setTitle(savedInstanceState.getString("activetitle"));
107 Bundle contextVars = savedInstanceState.getBundle("savedContextVariables");
108 if(contextVars != null) {
109 Bundle contextVariables = AppContext.getContextVariables();
110 contextVariables.putAll(contextVars);
115 if(instantRestore) // orientation change
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);
125 public void onSaveInstanceState(Bundle savedInstanceState) {
126 Log.i("CampusApp", "Event: onSaveInstanceState");
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());
135 Bundle contextVariables = AppContext.getContextVariables();
136 savedInstanceState.putBundle("savedContextVariables", contextVariables);
138 // Always call the superclass so it can save the view hierarchy state
139 super.onSaveInstanceState(savedInstanceState);
142 public void prepareMainUi() {
143 ImageView btnOpenSearch = (ImageView) findViewById(R.id.search_button);
144 btnOpenSearch.setVisibility(View.GONE);
147 public void loadMainUi() {
148 ImageView btnOpenSearch = (ImageView) findViewById(R.id.search_button);
150 btnOpenSearch.setVisibility(View.VISIBLE);
152 setupSearchTriggers();
154 AppContext.getNfcCardListener().startNfcListener();
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);
164 NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
165 navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
166 @SuppressWarnings("StatementWithEmptyBody")
168 public boolean onNavigationItemSelected(MenuItem item) {
169 // Handle navigation view item clicks here.
170 int id = item.getItemId();
172 for(CampusAppContext.NavigationItem navitem : AppContext.NAVIGATION_TARGETS) {
173 if(navitem.navItemId == id) {
174 AppContext.getNavigationManager().navigatePage(navitem.navTarget);
179 DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
180 drawer.closeDrawer(GravityCompat.START);
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);
192 // EventListener für Suchfunktion
193 btnOpenSearch.setOnClickListener(new View.OnClickListener() {
195 public void onClick(View view) {
196 triggerSearchPanel(true);
199 edtSearchInput.setOnFocusChangeListener(new View.OnFocusChangeListener() {
201 public void onFocusChange(View v, boolean hasFocus) {
202 EditText edtSearchInput = (EditText) v;
203 if (!hasFocus && edtSearchInput.getText().length() == 0) {
204 triggerSearchPanel(false);
208 edtSearchInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
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);
220 btnCloseSearch.setOnClickListener(new View.OnClickListener() {
222 public void onClick(View view) {
223 EditText edtSearchInput = (EditText) findViewById(R.id.search_input);
224 edtSearchInput.setText("");
225 triggerSearchPanel(false);
228 txtTitle.setOnClickListener(new View.OnClickListener() {
230 public void onClick(View view) {
231 triggerSearchPanel(true);
237 private void triggerSearchPanel(boolean show) {
238 if(bSearchActive == show)
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);
245 InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
247 layTitleContainer.setVisibility(View.GONE);
248 laySearchContainer.setVisibility(View.VISIBLE);
249 edtSearchInput.requestFocus();
251 imm.showSoftInput(edtSearchInput, InputMethodManager.SHOW_IMPLICIT);
253 layTitleContainer.setVisibility(View.VISIBLE);
254 laySearchContainer.setVisibility(View.GONE);
256 View view = this.getCurrentFocus();
258 imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
263 private void triggerSearchAction(String query) {
264 Bundle bundle = new Bundle();
265 bundle.putString("query", query);
267 AppContext.getNavigationManager().navigatePage("AppSearch", bundle);
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()
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);
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();
294 //noinspection SimplifiableIfStatement
295 if (id == R.id.action_settings) {
299 return super.onOptionsItemSelected(item);
302 /* nfc listener related callbacks */
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);
310 AppContext.setMainActivity(this);
313 Log.i("CampusApp", "onResume event");
314 AppContext.getNfcCardListener().resumeForefrontDispatcher();
318 public void onPause() {
320 Log.i("CampusApp", "Event: onPause");
321 AppContext.getNfcCardListener().pauseForefrontDispatcher();
325 public void onNewIntent(Intent intent) {
326 if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
327 AppContext.getNfcCardListener().handleNfcEvent(intent);