Java tutorial
/* * Copyright 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License atge * * http://www.apache.org/licenses/LINSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.denel.facepatrol; import android.app.*; import android.content.*; import android.net.*; import android.os.*; import android.support.v4.app.*; import android.support.v4.view.*; import android.util.*; import android.view.*; import android.widget.*; import java.io.*; import java.net.*; import java.security.*; import java.security.spec.*; import java.util.zip.*; import javax.crypto.*; import javax.crypto.spec.*; import android.app.FragmentTransaction; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; public class MainActivity extends FragmentActivity implements ContactList.onContactItemListener, ActionBar.TabListener { /** * The {@link android.support.v4.view.PagerAdapter} that will provide fragments for each of the * three primary sections of the app. We use a {@link android.support.v4.app.FragmentPagerAdapter} * derivative, which will keep every loaded fragment in memory. If this becomes too memory * intensive, it may be best to switch to a {@link android.support.v4.app.FragmentStatePagerAdapter}. */ AppSectionsPagerAdapter mAppSectionsPagerAdapter; /** * The {@link ViewPager} that will display the three primary sections of the app, one at a * time. */ ViewPager mViewPager; String contact_phone, contact_email, feedback_subject, feedback_body; Context mycontext; String pass1_text = null; SecretKey skey = null; String dbname = "DenelDB"; String dbname_en = "EncryptDB"; boolean is_db_encrypted = false; // This is for checking external storage for pictures BroadcastReceiver mExternalStorageReceiver; boolean mExternalStorageAvailable = false; boolean mExternalStorageWritable = false; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mycontext = getApplicationContext(); // Create the adapter that will return a fragment for each of the three primary sections // of the app. mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager()); // Set up the action bar. final ActionBar actionBar = getActionBar(); // Specify that the Home/Up button should not be enabled, since there is no hierarchical // parent. actionBar.setHomeButtonEnabled(false); // Specify that we will be displaying tabs in the action bar. actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Set up the ViewPager, attaching the adapter and setting up a listener for when the // user swipes between sections. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mAppSectionsPagerAdapter); mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { // When swiping between different app sections, select the corresponding tab. // We can also use ActionBar.Tab#select() to do this if we have a reference to the // Tab. actionBar.setSelectedNavigationItem(position); } }); // For each of the sections in the app, add a tab to the action bar. for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) { // Create a tab with text corresponding to the page title defined by the adapter. // Also specify this Activity object, which implements the TabListener interface, as the // listener for when this tab is selected. actionBar.addTab( actionBar.newTab().setText(mAppSectionsPagerAdapter.getPageTitle(i)).setTabListener(this)); } } @Override protected void onStart() { // TODO: Implement this method super.onStart(); Bundle bundle; bundle = getIntent().getExtras(); if (bundle != null) { pass1_text = bundle.getString("passw"); try { if (pass1_text != null) { skey = generateKey(pass1_text.toCharArray(), "sdf764rew51sdr98d2".getBytes()); } } catch (NoSuchAlgorithmException | InvalidKeySpecException f) { Log.e(null, "Unable to generate key throws Exception"); } } } @Override protected void onPause() { // TODO: Implement this method super.onPause(); // encrypt data // create secret key based on password if (!is_db_encrypted) { try { encryptfile(getApplicationContext(), skey); } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException ex) { Log.e(null, "Unable to encrypt file throws Exception"); } is_db_encrypted = true; } } @Override protected void onResume() { // TODO: Implement this method super.onResume(); // decrypt data if (is_db_encrypted) { try { decryptfile(getApplicationContext(), skey); } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException ex) { Log.e(null, "Unable to decrypt file throws Exception"); } is_db_encrypted = false; } } @Override protected void onStop() { // TODO: Implement this method super.onStop(); // encrypt data if (!is_db_encrypted) { try { encryptfile(getApplicationContext(), skey); } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException ex) { Log.e(null, "Unable to encrypt file throws Exception"); } is_db_encrypted = true; } } @Override protected void onRestart() { // TODO: Implement this method super.onRestart(); //decrypt data if (is_db_encrypted) { try { decryptfile(getApplicationContext(), skey); } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException ex) { Log.e(null, "Unable to decrypt file throws Exception"); } is_db_encrypted = false; } } /* This method is used to download the zip files of contact pictures and store them in a folder for further use. */ private void downloadunzip() throws IOException { // for now the file is from assets but will be downloaded later String PATH = getApplicationContext().getDir("pictures", 0).getAbsolutePath() + "/"; InputStream is = getApplicationContext().getAssets().open("ContactsPics.zip"); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is)); try { ZipEntry ze; byte[] buffer = new byte[1024]; while ((ze = zis.getNextEntry()) != null) { if (ze.isDirectory()) { _dirchecker((ze.getName())); } else { FileOutputStream baos = new FileOutputStream(PATH + ze.getName()); BufferedInputStream in = new BufferedInputStream(zis); BufferedOutputStream out = new BufferedOutputStream(baos); int count; while ((count = in.read(buffer)) > 0) { out.write(buffer, 0, count); } zis.closeEntry(); out.close(); } } } finally { zis.close(); } } private void _dirchecker(String dir) { File f = new File(getApplicationContext().getDir("pictures", 0).getAbsolutePath() + "/" + dir); if (!f.isDirectory()) { f.mkdirs(); } } public void onGroupEmail(String[] email_grp) { // enter code here Intent emailIntent = new Intent(Intent.ACTION_SENDTO); emailIntent.setData(Uri.parse("mailto:")); emailIntent.putExtra(Intent.EXTRA_EMAIL, email_grp); //emailIntent.setType("message/rfc822"); emailIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); startActivity(Intent.createChooser(emailIntent, "Send Group Email...")); } @Override public void onContactSelected(Bundle args) { contact_phone = args.getString("phone"); contact_email = args.getString("email"); feedback_body = "Face Patrol - Contact Update: " + args.getString("name") + " " + args.getString("surname"); feedback_subject = "Please edit the contact information below BEFORE submission \n\n" + "Name: " + args.getString("name") + " " + args.getString("surname") + "\n" + "Division: " + args.getString("division") + "\n" + "Department: " + args.getString("dept") + "\n" + "Title: " + args.getString("title") + "\n" + "Products Expertise: " + args.getString("product") + "\n" + "Regions: " + args.getString("region") + "\n" + "Work Interests: " + args.getString("work_int") + "\n" + "Personal Interests: " + args.getString("personal") + "\n" + "Birthday: " + args.getString("birthday") + "\n" + "Phone No: " + args.getString("phone") + "\n" + "Email Address: " + args.getString("email") + "\n"; } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { } @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { // When the given tab is selected, switch to the corresponding page in the ViewPager. mViewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { } /** * A {@link FragmentPagerAdapter} that returns a fragment corresponding to one of the primary * sections of the app. */ public static class AppSectionsPagerAdapter extends FragmentPagerAdapter { public AppSectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { switch (i) { case 0: return new ContactList(); case 1: return new ProductsFragment(); case 2: return new ServicesFragment(); default: return new ContactList(); } } @Override public int getCount() { return 2; } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return "Contact Search"; case 1: return "Products & Services"; case 2: return "Services"; } return null; } } // ImageView onClick methods public void ContactPhone(View view) { Intent phoneIntent = new Intent(Intent.ACTION_DIAL); phoneIntent.setData(Uri.parse("tel:" + contact_phone)); phoneIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); startActivity(Intent.createChooser(phoneIntent, "Phone Number")); //finish(); } public void ContactEmail(View view) { Intent emailIntent = new Intent(Intent.ACTION_SENDTO); emailIntent.setData(Uri.parse("mailto:")); emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { contact_email }); //emailIntent.setType("message/rfc822"); emailIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); startActivity(Intent.createChooser(emailIntent, "Send Email...")); //finish(); } public void ContactEdit(View view) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Contact Information Feedback") .setMessage("You're about to edit and send personal information. " + "Please note that the current database will only reflect your modification" + " once the IT department verifies the change and the updated database" + " is synced to your device. \n \n Do you want to continue?") .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Intent emailIntent = new Intent(Intent.ACTION_SENDTO); emailIntent.setData(Uri.parse("mailto:")); emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { "pkantue@gmail.com" }); // this email address will change emailIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); emailIntent.putExtra(Intent.EXTRA_SUBJECT, feedback_subject); emailIntent.putExtra(Intent.EXTRA_TEXT, feedback_body); startActivity(Intent.createChooser(emailIntent, "Send Email...")); } }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // User cancelled the dialog } }); builder.show(); // exit the application //finish(); } // generate secretkey with a user-password or pin private static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException { // Number of PBKDF2 hardening rounds to use. Larger values increase // computation time. You should select a value that causes computation // to take >100ms. final int iterations = 1000; // Generate a 256-bit key final int outputKeyLength = 256; SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength); SecretKey secretKey = secretKeyFactory.generateSecret(keySpec); return secretKey; } public void copydatabase(Context mcontext) { String dbname = "DenelDB"; File outfile = mcontext.getDatabasePath(dbname); if (outfile.exists()) { return; } outfile = mcontext.getDatabasePath(dbname + ".temp"); // parent directory for his file if it doesn't exist, // in this case it returns a false. outfile.getParentFile().mkdirs(); try { InputStream instream = mcontext.getAssets().open(dbname); OutputStream outstream = new FileOutputStream(outfile); //transfer bytes from instream to outstream byte[] buffer = new byte[1024]; int length; while ((length = instream.read(buffer)) > 0) { outstream.write(buffer, 0, length); } outstream.flush(); outstream.close(); instream.close(); outfile.renameTo(mcontext.getDatabasePath(dbname)); } catch (IOException e) { if (outfile.exists()) { outfile.delete(); } } } private void startDownload() { String url = "http://enter_link_to_database_file"; new DownloadFileAsync().execute(url); } private void encryptfile(Context mcontext, SecretKey key) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { // This will probably change when I will the database will be downloaded from the server boolean db_file_exists = mcontext.getDatabasePath(dbname).exists(); InputStream fis = null; File infile = mcontext.getDatabasePath(dbname); // check if database file exists to prevent downloading the file each start if (db_file_exists) { fis = new FileInputStream(infile); } else { fis = mcontext.getAssets().open(dbname); } // This stream write the encrypted text. This stream will be wrapped by another stream. FileOutputStream fos = new FileOutputStream(mcontext.getDatabasePath(dbname_en).getAbsolutePath()); // Length is 16 byte // Careful when taking user input!!! http://stackoverflow.com/a/3452620/1188357 SecretKeySpec sks = new SecretKeySpec(key.getEncoded(), "AES"); // Create cipher Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, sks); // Wrap the output stream CipherOutputStream cos = new CipherOutputStream(fos, cipher); // Write bytes int b; byte[] d = new byte[8]; while ((b = fis.read(d)) != -1) { cos.write(d, 0, b); } // Flush and close streams. cos.flush(); cos.close(); fis.close(); // delete the decrypted file if (infile.exists()) { infile.delete(); } } private void decryptfile(Context mcontext, SecretKey key) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { File infile = mcontext.getDatabasePath(dbname_en); InputStream fis = new FileInputStream(infile); File outfile = mcontext.getDatabasePath(dbname); // parent directory for his file if it doesn't exist, // in this case it returns a false. outfile.getParentFile().mkdirs(); // This stream write the decrypted text. This stream will be wrapped by another stream. FileOutputStream fos = new FileOutputStream(outfile); // Length is 16 byte // Careful when taking user input!!! // http://stackoverflow.com/a/3452620/1188357 SecretKeySpec sks = new SecretKeySpec(key.getEncoded(), "AES"); // Create cipher Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, sks); // Wrap the output stream CipherOutputStream cos = new CipherOutputStream(fos, cipher); // Write bytes int b; byte[] d = new byte[8]; while ((b = fis.read(d)) != -1) { cos.write(d, 0, b); } // Flush and close streams. cos.flush(); cos.close(); fis.close(); // delete the encrypted file if (infile.exists()) { infile.delete(); } } private void updateExternalStorageState() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { mExternalStorageAvailable = mExternalStorageWritable = true; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { mExternalStorageAvailable = true; mExternalStorageWritable = false; } else { mExternalStorageAvailable = mExternalStorageWritable = false; } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate main_menu.xml MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); return true; } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { // TODO: Implement this method switch (item.getItemId()) { case R.id.action_settings: Intent intent1 = new Intent(this, Settings.class); startActivity(intent1); return true; case R.id.action_download: try { downloadunzip(); } catch (IOException e) { } return true; case R.id.main_help: // start activity using dummy class run_quick_tips(); //Intent intent = new Intent(this,dummypage.class); //intent.putExtra("title","Help"); //startActivity(intent); return true; case R.id.main_about: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("About").setMessage(R.string.about).setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // FIRE ZE MISSILES! } }); //.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { // public void onClick(DialogInterface dialog, int id) { // User cancelled the dialog //} }); builder.show(); return true; case R.id.action_exit: // exit the application finish(); return true; } return super.onMenuItemSelected(featureId, item); } public void run_quick_tips() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Quick Tips").setMessage(R.string.quick_tips).setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // FIRE ZE MISSILES! } }); //.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { // public void onClick(DialogInterface dialog, int id) { // User cancelled the dialog //} }); builder.show(); } class DownloadFileAsync extends AsyncTask<String, String, String> { @Override protected void onPreExecute() { super.onPreExecute(); //showDialog(DIALOG_DOWNLOAD_PROGRESS); } @Override protected String doInBackground(String... f_url) { // TODO: Implement this method int count; try { URL url = new URL(f_url[0]); URLConnection connection = url.openConnection(); connection.connect(); // Get Music file length int lenghtOfFile = connection.getContentLength(); // input stream to read file - with 8k buffer InputStream input = new BufferedInputStream(url.openStream(), 10 * 1024); // Output stream to write file in SD card OutputStream output = new FileOutputStream( Environment.getExternalStorageDirectory().getPath() + "file_name.ext"); byte data[] = new byte[1024]; long total = 0; while ((count = input.read(data)) != -1) { total += count; // Publish the progress which triggers onProgressUpdate //publishProgress( "" + ( int ) ((total * 100) / lenghtOfFil // Write data to file output.write(data, 0, count); } // Flush output output.flush(); // Close streams output.close(); input.close(); } catch (Exception e) { Log.e("Error: ", e.getMessage()); } return null; } } }