Java tutorial
/* * Copyright (c) 2014 Jakob Wenzel, Ramon Wirsch. * * This file is part of RallyeSoft. * * RallyeSoft 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. * * RallyeSoft 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 RallyeSoft. If not, see <http://www.gnu.org/licenses/>. */ package de.stadtrallye.rallyesoft; import android.app.Activity; import android.app.LoaderManager; import android.content.CursorLoader; import android.content.Intent; import android.content.Loader; import android.database.Cursor; import android.nfc.NdefMessage; import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.Parcelable; import android.provider.ContactsContract; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.Window; import android.widget.Toast; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult; import java.util.ArrayList; import de.rallye.model.structures.ServerLogin; import de.stadtrallye.rallyesoft.common.Std; import de.stadtrallye.rallyesoft.fragments.AssistantAuthFragment; import de.stadtrallye.rallyesoft.fragments.AssistantCompleteFragment; import de.stadtrallye.rallyesoft.fragments.AssistantGroupsFragment; import de.stadtrallye.rallyesoft.fragments.AssistantServerFragment; import de.stadtrallye.rallyesoft.model.Server; import de.stadtrallye.rallyesoft.storage.Storage; import de.stadtrallye.rallyesoft.uimodel.IConnectionAssistant; import de.stadtrallye.rallyesoft.util.converters.Serialization; /** * Activity that hosts an IConnectionAssistant and several Fragments containing the guided login * User inputs and server configurations are saved here, so they can be accessed from all pages of the assistant */ public class ConnectionAssistantActivity extends ActionBarActivity implements IConnectionAssistant, LoaderManager.LoaderCallbacks<Cursor> { public static final int REQUEST_CODE = 1336; private static final String THIS = ConnectionAssistantActivity.class.getSimpleName(); private ArrayList<FragmentHandler<?>> steps; private int step = 1; private boolean fastForward = false; private Server server; private String name; private String suggestedName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Title and Content supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setTitle(R.string.connection_assistant); // setContentView(R.layout.connection_assistant); ActionBar ab = getSupportActionBar(); ab.setDisplayHomeAsUpEnabled(true); ab.setDisplayShowTitleEnabled(true); Storage.aquireStorage(getApplicationContext(), this); if (savedInstanceState != null) { step = savedInstanceState.getInt(Std.STEP); server = Server.load(savedInstanceState.getString(Std.SERVER)); name = savedInstanceState.getString(Std.NAME); } //Create FragmentHandlers steps = new ArrayList<FragmentHandler<?>>(); steps.add(new FragmentHandler<AssistantServerFragment>("server", AssistantServerFragment.class)); steps.add(new FragmentHandler<AssistantGroupsFragment>("groups", AssistantGroupsFragment.class)); steps.add(new FragmentHandler<AssistantAuthFragment>("auth", AssistantAuthFragment.class)); steps.add(new FragmentHandler<AssistantCompleteFragment>("complete", AssistantCompleteFragment.class)); getLoaderManager().initLoader(0, null, this); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); return true; case R.id.scan_qr_login: IntentIntegrator zx = new IntentIntegrator(this); zx.initiateScan(IntentIntegrator.QR_CODE_TYPES); return true; } return false; } private static final String[] PROFILE_PROJECTION = { ContactsContract.Profile.DISPLAY_NAME_PRIMARY }; @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return new CursorLoader(getApplicationContext(), ContactsContract.Profile.CONTENT_URI, PROFILE_PROJECTION, null, null, null); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { data.moveToFirst(); if (!data.isAfterLast()) suggestedName = data.getString(0); } @Override public void onLoaderReset(Loader<Cursor> loader) { } @Override public String getSuggestedName() { return suggestedName; } /** * Envelops a Fragment, reuses a already existing Fragment otherwise instantiates a new one * @author Ramon * * @param <T> Fragment Type to envelop */ private class FragmentHandler<T extends Fragment> { private final String tag; private final Class<T> clz; private Bundle arg; public FragmentHandler(String tag, Class<T> clz) { this.tag = tag; this.clz = clz; } // --Commented out by Inspection START (22.09.13 02:46): // public void setArguments(Bundle arg) { // this.arg = arg; // } // --Commented out by Inspection STOP (22.09.13 02:46) public Fragment getFragment() { Fragment f = getSupportFragmentManager().findFragmentByTag(tag); if (f == null) { if (arg == null) f = Fragment.instantiate(ConnectionAssistantActivity.this, clz.getName()); else f = Fragment.instantiate(ConnectionAssistantActivity.this, clz.getName(), arg); } return f; } public String getTag() { return tag; } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuItem scan_qr = menu.add(Menu.NONE, R.id.scan_qr_login, 10, R.string.scan_barcode); scan_qr.setIcon(R.drawable.ic_scan_qr_light); scan_qr.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); return true; } @Override protected void onStart() { super.onStart(); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); FragmentHandler<?> f = steps.get(step - 1); ft.replace(android.R.id.content, f.getFragment(), f.getTag()).commit(); if (fastForward) { while (step < steps.size() - 1) { next(); } } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(Std.STEP, step); outState.putString(Std.SERVER, (server != null) ? server.serialize() : null); outState.putString(Std.NAME, name); } @Override protected void onResume() { super.onResume(); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { processNfcIntent(getIntent()); } } @Override protected void onNewIntent(Intent intent) { setIntent(intent); } /** * Extract login info from JSON * @param serverLoginJSON */ private void readServerLoginJSON(String serverLoginJSON) { ServerLogin l; try { ObjectMapper mapper = Serialization.getJsonInstance(); l = mapper.readValue(serverLoginJSON, ServerLogin.class); String serverWithoutSlash = l.getAddress(); if (serverWithoutSlash.endsWith("/")) { serverWithoutSlash = serverWithoutSlash.substring(0, serverWithoutSlash.length() - 1); } setServer(new Server(serverWithoutSlash)); setGroup(l.getGroupID()); server.setGroupPassword(l.getGroupPassword()); fastForward = true; } catch (Exception e) { Log.e(THIS, "Could not deserialize ServerLogin from JSON", e); Toast.makeText(this, getString(R.string.no_valid_login), Toast.LENGTH_SHORT).show(); } } private void processNfcIntent(Intent intent) { Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); // only one message sent during the beam NdefMessage msg = (NdefMessage) rawMsgs[0]; readServerLoginJSON(new String(msg.getRecords()[0].getPayload())); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == IntentIntegrator.REQUEST_CODE) { IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (scanResult == null) return; if (resultCode == Activity.RESULT_OK && scanResult.getContents() != null) readServerLoginJSON(scanResult.getContents()); } } @Override public void back() { getSupportFragmentManager().popBackStack(); step--; } @Override public void setNameAndPass(String name, String pass) { this.name = name; server.setGroupPassword(pass); } @Override public Integer getGroup() { return server.getGroupID(); } @Override public String getPass() { return server.getGroupPassword(); } @Override public String getName() { return name; } @Override public void next() { if (step < steps.size()) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); FragmentHandler<?> f = steps.get(step); ft.replace(android.R.id.content, f.getFragment(), f.getTag()).addToBackStack(null) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit(); step++; } } @Override public void onBackPressed() { super.onBackPressed(); step--; } @Override public void setServer(Server server) { this.server = server; } @Override public Server getServer() { return server; } @Override public void setGroup(int groupID) { server.setGroupID(groupID); } @Override public void finish(boolean acceptNewConnection) { if (acceptNewConnection && server.hasUserAuth()) { Server.setCurrentServer(server); } else { //server.destroy(); } setResult((acceptNewConnection) ? Activity.RESULT_OK : Activity.RESULT_CANCELED); super.finish(); } @Override protected void onDestroy() { Storage.releaseStorage(this); super.onDestroy(); } /** * IProgressUI */ @Override public void activateProgressAnimation() { setProgressBarIndeterminateVisibility(true); } /** * IProgressUI */ @Override public void deactivateProgressAnimation() { setProgressBarIndeterminateVisibility(false); } }