Java tutorial
/* This file is part of ZAX. ZAX is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ZAX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with ZAX. If not, see <http://www.gnu.org/licenses/>. */ package com.inovex.zabbixmobile.activities; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.preference.PreferenceActivity; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.TextView; import com.inovex.zabbixmobile.OnSettingsMigratedReceiver; import com.inovex.zabbixmobile.R; import com.inovex.zabbixmobile.adapters.BaseServiceAdapter; import com.inovex.zabbixmobile.data.ZabbixDataService; import com.inovex.zabbixmobile.data.ZabbixDataService.OnLoginProgressListener; import com.inovex.zabbixmobile.data.ZabbixDataService.ZabbixDataBinder; import com.inovex.zabbixmobile.model.ZabbixServer; import com.inovex.zabbixmobile.model.ZaxPreferences; import com.inovex.zabbixmobile.push.pubnub.PubnubPushService; import com.inovex.zabbixmobile.widget.WidgetUpdateBroadcastReceiver; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import de.duenndns.ssl.MemorizingTrustManager; /** * Base class for all activities. Tasks performed in this class: * <p/> * * Show the navigation drawer * <p/> * * initiate the connection to the data service and perform the Zabbix login * <p/> * * open the settings dialog */ public abstract class BaseActivity extends AppCompatActivity implements ServiceConnection, OnLoginProgressListener, NavigationView.OnNavigationItemSelectedListener, AdapterView.OnItemSelectedListener, View.OnClickListener { private static final int REQUEST_CODE_PREFERENCES = 12345; public static final int RESULT_PREFERENCES_CHANGED = 1; protected ZabbixDataService mZabbixDataService; protected String mTitle; protected DrawerLayout mDrawerLayout; protected ActionBarDrawerToggle mDrawerToggle; protected Toolbar mToolbar; protected Toolbar mHostgroupToolbar; protected NavigationView mNavigationView; private LoginProgressDialogFragment mLoginProgress; private boolean mPreferencesClosed = false; private boolean mPreferencesChangedServer = false; private boolean mPreferencesChangedPush = false; private boolean mPreferencesChangedWidget = false; private boolean mServerSelectMode = false; private boolean mPreferencesChangedTheme = false; private boolean mOnSaveInstanceStateCalled = false; private static final String TAG = BaseActivity.class.getSimpleName(); private FinishReceiver finishReceiver; private boolean mDrawerOpened = false; public static final int ACTIVITY_SCREENS = 3; public static final int ACTIVITY_CHECKS = 2; public static final int ACTIVITY_EVENTS = 1; public static final int ACTIVITY_PROBLEMS = 0; public static final int MESSAGE_SSL_ERROR = 0; private static final String ACTION_FINISH = "com.inovex.zabbixmobile.BaseActivity.ACTION_FINISH"; private OnSettingsMigratedReceiver mOnSettingsMigratedReceiver; private BaseServiceAdapter<ZabbixServer> mServersListAdapter; private TextView mServerNameView; private ImageButton mServerSelectButton; private View mServerNameLayout; private long persistedServerSelection; @Override public boolean onNavigationItemSelected(MenuItem menuItem) { Intent intent; if (menuItem.isChecked()) menuItem.setChecked(false); else menuItem.setChecked(true); if (mServerSelectMode) { selectServerItem(menuItem.getItemId()); toggleServerSelectionMode(); return true; } //Closing drawer on item click switch (menuItem.getItemId()) { case R.id.navigation_item_problems: intent = new Intent(this, ProblemsActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); mDrawerLayout.closeDrawers(); break; case R.id.navigation_item_events: intent = new Intent(this, EventsActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); mDrawerLayout.closeDrawers(); break; case R.id.navigation_item_checks: intent = new Intent(this, ChecksActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); mDrawerLayout.closeDrawers(); break; case R.id.navigation_item_screens: intent = new Intent(this, ScreensActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); mDrawerLayout.closeDrawers(); break; case R.id.navigation_settings: intent = new Intent(this, ZaxPreferenceActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivityForResult(intent, REQUEST_CODE_PREFERENCES); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); return true; case R.id.navigation_manage_servers: intent = new Intent(this, ServersActivity.class); break; case R.id.navigation_info: intent = new Intent(this, InfoActivity.class); break; default: return true; } startActivity(intent); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); // update selected item and title, then close the drawer //mDrawerFragment.selectMenuItem(position); return true; } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectServerItem(id); // persist selection // ZaxPreferences.getInstance(getApplicationContext()) // .setServerSelection(id); Log.d(TAG, "selected server id=" + id); this.refreshData(); } @Override public void onNothingSelected(AdapterView<?> parent) { } @Override public void onClick(View v) { switch (v.getId()) { case R.id.navigation_button_serverselect: case R.id.server_name_layout: toggleServerSelectionMode(); break; } } private void toggleServerSelectionMode() { Menu menu = mNavigationView.getMenu(); if (mServerSelectMode) { // show normal menu menu.setGroupVisible(R.id.grp1, true); menu.setGroupVisible(R.id.grp2, true); menu.removeGroup(R.id.grp0_server); mServerSelectButton.setImageDrawable(getResources().getDrawable(R.drawable.spinner_triangle)); } else { // show server selection list menu.setGroupVisible(R.id.grp1, false); menu.setGroupVisible(R.id.grp2, false); for (int i = 0; i < mServersListAdapter.getCount(); i++) { ZabbixServer server = mServersListAdapter.getItem(i); menu.add(R.id.grp0_server, (int) server.getId(), Menu.NONE, server.getName()) .setIcon(R.drawable.ic_monitor_grey600_24dp); } mServerSelectButton.setImageDrawable(getResources().getDrawable(R.drawable.spinner_triangle_flipped)); } mServerSelectMode = !mServerSelectMode; } /** * Broadcast receiver that finishes an activity. */ private final class FinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(ACTION_FINISH)) finish(); } } /** * If the server settings have not been set yet by the user, a dialog is * displayed. Otherwise, the Zabbix login is performed. */ @SuppressLint("ValidFragment") @Override public void onServiceConnected(ComponentName className, IBinder binder) { Log.d(TAG, "onServiceConnected: " + this.getLocalClassName() + " " + this.toString()); ZabbixDataBinder zabbixBinder = (ZabbixDataBinder) binder; mZabbixDataService = zabbixBinder.getService(); mZabbixDataService.setActivityContext(BaseActivity.this); mZabbixDataService.loadZabbixServers(); // sync // if there are no servers configurated if (mZabbixDataService.getServersListManagementAdapter().isEmpty()) { new DialogFragment() { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.dialog_default_settings, null); builder.setView(view); builder.setTitle(R.string.server_data_not_set); // Add action buttons builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { // create default zabbix server ZabbixServer srv = mZabbixDataService.createNewZabbixServer("default"); ZaxPreferences.getInstance(getApplicationContext()).setServerSelection(srv.getId()); Intent intent = new Intent(getApplicationContext(), ZabbixServerPreferenceActivity.class); intent.putExtra(ZabbixServerPreferenceActivity.ARG_ZABBIX_SERVER_ID, srv.getId()); getActivity().startActivityForResult(intent, REQUEST_CODE_PREFERENCES); } }); return builder.create(); } }.show(getSupportFragmentManager(), "DefaultSettingsDialogFragment"); // return to avoid a login with incorrect credentials return; } mZabbixDataService.performZabbixLogin(this); mServersListAdapter = mZabbixDataService.getServersSelectionAdapter(); ZabbixServer server = mServersListAdapter.getItem(mServersListAdapter.getCurrentPosition()); setServerViews(server.getName()); mServerSelectButton.setOnClickListener(this); mServerNameLayout.setOnClickListener(this); updateCurrentServerNameView(); // restoreServerSelection(); } @Override public void onServiceDisconnected(ComponentName arg0) { Log.d(TAG, "onServiceDisconnected()"); mZabbixDataService = null; } @Override protected void onPause() { super.onPause(); ZaxPreferences.getInstance(this).setServerSelection(this.persistedServerSelection); Log.d(TAG, "onPause"); } /** * If settings have been changed, this method clears all cached data and * initiates a fresh login. */ @Override protected void onResume() { super.onResume(); Log.d(TAG, "onResume"); ZaxPreferences preferences = ZaxPreferences.getInstance(this); this.persistedServerSelection = preferences.getServerSelection(); this.setServerViews(preferences.getPersistedServerName()); // if the preferences activity has been closed, we check which // preferences have been changed and perform necessary actions if (mPreferencesClosed) { if (mPreferencesChangedServer && mZabbixDataService != null) { mZabbixDataService.performZabbixLogout(); mZabbixDataService.clearAllData(); mZabbixDataService.initConnection(); // update widget because server data has changed mServersListAdapter = mZabbixDataService.getServersSelectionAdapter(); Intent intent = new Intent(getApplicationContext(), WidgetUpdateBroadcastReceiver.class); this.sendBroadcast(intent); mZabbixDataService.performZabbixLogin(this); mPreferencesChangedServer = false; restoreServerSelection(); } if (mPreferencesChangedTheme) { mPreferencesChangedTheme = false; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { // clear activity history and restart this activity Intent restartIntent = getIntent(); restartIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); finish(); startActivity(restartIntent); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); } else { // as FLAG_ACTIVITY_CLEAR_TASK is not available on Android < // version 11, we manually send a broadcast to clear the // activity history sendBroadcast(new Intent(ACTION_FINISH)); Intent restartIntent = getIntent(); restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(restartIntent); } } mPreferencesClosed = false; } else { PubnubPushService.startOrStopPushService(getApplicationContext()); } updateCurrentServerNameView(); } private void updateCurrentServerNameView() { if (mZabbixDataService != null) { ZabbixServer server = mZabbixDataService.getServerById(persistedServerSelection); if (server != null) { setServerViews(server.getName()); } else { Log.d(TAG, "Error: Persisted ServerID was not found!"); } } } /** * Binds the Zabbix service. */ protected void bindService() { Intent intent = new Intent(this, ZabbixDataService.class); boolean useMockData = getIntent().getBooleanExtra(ZabbixDataService.EXTRA_IS_TESTING, false); intent.putExtra(ZabbixDataService.EXTRA_IS_TESTING, useMockData); getApplicationContext().bindService(intent, this, Context.BIND_AUTO_CREATE); } /** * Binds the data service and sets up the action bar. */ @Override protected void onCreate(Bundle savedInstanceState) { ZaxPreferences prefs = ZaxPreferences.getInstance(getApplicationContext()); if (prefs.isDarkTheme()) setTheme(R.style.AppThemeDark); else setTheme(R.style.AppTheme); super.onCreate(savedInstanceState); finishReceiver = new FinishReceiver(); registerReceiver(finishReceiver, new IntentFilter(ACTION_FINISH)); bindService(); // (re-) instantiate progress dialog mLoginProgress = (LoginProgressDialogFragment) getSupportFragmentManager() .findFragmentByTag(LoginProgressDialogFragment.TAG); if (mLoginProgress == null) { mLoginProgress = LoginProgressDialogFragment.getInstance(); } try { SSLContext sc = SSLContext.getInstance("TLS"); MemorizingTrustManager mtm = new MemorizingTrustManager(this); sc.init(null, new X509TrustManager[] { mtm }, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier( mtm.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier())); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } } /** * Inflates a base layout containing the navigation drawer and incorporates * the given layout resource into this base layout. */ @Override public void setContentView(final int layoutResID) { mDrawerLayout = (DrawerLayout) getLayoutInflater().inflate(R.layout.activity_base, null); FrameLayout content = (FrameLayout) mDrawerLayout.findViewById(R.id.content_frame); getLayoutInflater().inflate(layoutResID, content, true); mServerNameView = (TextView) mDrawerLayout.findViewById(R.id.navigation_text_servername); mServerSelectButton = (ImageButton) mDrawerLayout.findViewById(R.id.navigation_button_serverselect); mServerNameLayout = mDrawerLayout.findViewById(R.id.server_name_layout); // set a custom shadow that overlays the main content when the drawer // opens mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); mNavigationView = (NavigationView) mDrawerLayout.findViewById(R.id.navigation); //Setting Navigation View Item Selected Listener to handle the item click of the navigation menu mNavigationView.setNavigationItemSelectedListener(this); // ActionBarDrawerToggle ties together the the proper interactions // between the sliding drawer and the action bar app icon mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */ mDrawerLayout, /* DrawerLayout object */ mToolbar, /* nav drawer image to replace 'Up' caret */ R.string.drawer_open, /* "open drawer" description for accessibility */ R.string.drawer_close /* "close drawer" description for accessibility */ ) { @Override public void onDrawerClosed(View view) { onNavigationDrawerClosed(); } @Override public void onDrawerOpened(View drawerView) { onNavigationDrawerOpened(); } }; mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); mDrawerToggle.setDrawerIndicatorEnabled(true); setContentView(mDrawerLayout); mDrawerToggle.syncState(); mToolbar = (Toolbar) findViewById(R.id.toolbar); mHostgroupToolbar = (Toolbar) findViewById(R.id.toolbar_hostgroup); // mToolbar.setTitle(mTitle); setSupportActionBar(mToolbar); getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle(mTitle); } /** * When using the ActionBarDrawerToggle, you must call it during * onPostCreate() and onConfigurationChanged()... */ @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggls mDrawerToggle.onConfigurationChanged(newConfig); } @Override protected void onStop() { super.onStop(); } /** * This unbinds the service if the application is exiting. */ @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); unregisterReceiver(finishReceiver); // TODO commented out because registration above is commented out // unregisterReceiver(mOnSettingsMigratedReceiver); if (isFinishing()) { Log.d(TAG, "unbindService"); getApplicationContext().unbindService(this); } } @Override public void onBackPressed() { // finish(); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); super.onBackPressed(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // The action bar home/up action should open or close the drawer. // ActionBarDrawerToggle will take care of this. switch (item.getItemId()) { case android.R.id.home: mDrawerLayout.openDrawer(GravityCompat.START); return true; case R.id.menuitem_clear: refreshData(); return true; } return super.onOptionsItemSelected(item); } /** * Clears all cached data and performs a fresh login. */ public void refreshData() { refreshData(true); } public void refreshData(boolean logout) { mZabbixDataService.clearAllData(logout); if (logout) { mZabbixDataService.performZabbixLogout(); // re-login and load host groups mZabbixDataService.performZabbixLogin(this); } } /** * Loads all data necessary for a view from Zabbix. */ protected abstract void loadData(); @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mOnSaveInstanceStateCalled = true; } @Override public void onLoginStarted() { if (!this.isFinishing() && !mOnSaveInstanceStateCalled && !mLoginProgress.isAdded()) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.show(mLoginProgress); ft.commitAllowingStateLoss(); // mLoginProgress.show(getSupportFragmentManager(), // LoginProgressDialogFragment.TAG); } } @Override public void onLoginFinished(boolean success, boolean showToast) { if (mLoginProgress != null && mLoginProgress.isAdded()) { try { mLoginProgress.dismiss(); } catch (NullPointerException e) { // in case the progress is not being shown right now, a // NullPointerException will be thrown, which we can safely // ignore. } catch (IllegalStateException e) { // if the activity has been canceled, this exception will be // thrown e.printStackTrace(); } } if (success) { // if (showToast) // Toast.makeText(this, R.string.zabbix_login_successful, // Toast.LENGTH_LONG).show(); loadData(); } } /** * If the finished activity is the {@link PreferenceActivity}, save the * status (preferences changed or not) to be used in onResume(). */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "onActivityResult: " + requestCode + " - " + resultCode); if (requestCode == REQUEST_CODE_PREFERENCES) { if ((resultCode & ZaxPreferenceActivity.PREFERENCES_CHANGED_SERVER) == ZaxPreferenceActivity.PREFERENCES_CHANGED_SERVER) { mPreferencesChangedServer = true; Log.d(TAG, "preferences changed: server"); } if ((resultCode & ZaxPreferenceActivity.PREFERENCES_CHANGED_PUSH) == ZaxPreferenceActivity.PREFERENCES_CHANGED_PUSH) { mPreferencesChangedPush = true; Log.d(TAG, "preferences changed: push"); } if ((resultCode & ZaxPreferenceActivity.PREFERENCES_CHANGED_WIDGET) == ZaxPreferenceActivity.PREFERENCES_CHANGED_WIDGET) { mPreferencesChangedWidget = true; Log.d(TAG, "preferences changed: widget"); } if ((resultCode & ZaxPreferenceActivity.PREFERENCES_CHANGED_THEME) == ZaxPreferenceActivity.PREFERENCES_CHANGED_THEME) { mPreferencesChangedTheme = true; Log.d(TAG, "preferences changed: theme"); } mPreferencesClosed = true; } } protected void onNavigationDrawerClosed() { //mToolbar.setTitle(mTitle); mDrawerOpened = false; supportInvalidateOptionsMenu(); } protected void onNavigationDrawerOpened() { //mToolbar.setTitle(R.string.app_name); mDrawerOpened = true; supportInvalidateOptionsMenu(); } /** * The login progress dialog. */ public static class LoginProgressDialogFragment extends DialogFragment { public static final String TAG = LoginProgressDialogFragment.class.getSimpleName(); public static LoginProgressDialogFragment getInstance() { return new LoginProgressDialogFragment(); } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { setRetainInstance(true); ProgressDialog loginProgress = new ProgressDialog(getActivity()); loginProgress.setTitle(R.string.zabbix_login); loginProgress.setMessage(getResources().getString(R.string.zabbix_login_in_progress)); loginProgress.setIndeterminate(true); return loginProgress; } } public void restoreServerSelection() { persistedServerSelection = ZaxPreferences.getInstance(getApplicationContext()).getServerSelection(); selectServerItem(persistedServerSelection); } protected void selectServerItem(long zabbixServerId) { for (int i = 0; i < mServersListAdapter.getCount(); i++) { if (mServersListAdapter.getItemId(i) == zabbixServerId && mServersListAdapter.getItemId(i) != persistedServerSelection) { mServersListAdapter.setCurrentPosition(i); setServerViews(mServersListAdapter.getItem(i).getName()); this.persistedServerSelection = mServersListAdapter.getItem(i).getId(); ZaxPreferences preferences = ZaxPreferences.getInstance(this); preferences.setServerSelection(persistedServerSelection); preferences.setPersistedServerName(mServersListAdapter.getItem(i).getName()); mZabbixDataService.setZabbixServer(persistedServerSelection); // this.mZabbixDataService.clearAllData(false); this.refreshData(); break; } } } protected void setServerViews(String name) { this.mServerNameView.setText(name); } }