Android Open Source - android-passwordKeeper Main Activity






From Project

Back to project page android-passwordKeeper.

License

The source code is released under:

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions...

If you think the Android project android-passwordKeeper listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * Copyright 2014 Cody Munger//from www.  ja  va2 s .  com
 *
 * 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 at
 *
 *   http://www.apache.org/licenses/LICENSE-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.munger.passwordkeeper;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentManager.BackStackEntry;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;

import com.dropbox.sync.android.DbxAccount;
import com.dropbox.sync.android.DbxAccountManager;
import com.munger.passwordkeeper.alert.AlertFragment;
import com.munger.passwordkeeper.alert.PasswordFragment;
import com.munger.passwordkeeper.struct.PasswordDetails;
import com.munger.passwordkeeper.struct.PasswordDocument;
import com.munger.passwordkeeper.struct.PasswordDocumentFile;
import com.munger.passwordkeeper.view.AboutFragment;
import com.munger.passwordkeeper.view.CreateFileFragment;
import com.munger.passwordkeeper.view.ImportFileFragment;
import com.munger.passwordkeeper.view.SelectFileFragment;
import com.munger.passwordkeeper.view.ViewDetailFragment;
import com.munger.passwordkeeper.view.ViewFileFragment;

/**
 * This is the main activity launched by the manifest.
 * MainActivity contains the fragments for creating new documents, importing documents, 
 * and viewing documents.
 *
 */
public class MainActivity extends ActionBarActivity 
{  
  static
  {
    System.loadLibrary("DropboxSync");
  }
  
  /** Fragment for selecting an existing document */ private SelectFileFragment selectFileFragment;
  /** Fragment for creating a new document */ private CreateFileFragment createFileFragment;
  /** Fragment for viewing an existing document */ private ViewFileFragment viewFileFragment;
  /** Fragment for viewing a detail in a document */ private ViewDetailFragment viewDetailFragment;
  /** Fragment for importing an external document */ private ImportFileFragment importFileFragment;
  
  private DbxAccountManager dropboxAcctMgr;
  private DbxAccount dropboxAcct;
  private boolean hasDropboxLink;
  private Object quitLock = new Object();
  private Long quitTime;
  private Long quitDelta = 90000L;
  private Thread quitThread;
  
  /**
   * Gather fragments and bring up the initial screen.
   */
  @Override
  protected void onCreate(Bundle savedInstanceState) 
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    //setup dropbox
      hasDropboxLink = false;
      dropboxAcctMgr = DbxAccountManager.getInstance(this.getApplicationContext(), "5xyvkb536ur7sue", "w6wthm9amap6xo4");

    if (dropboxAcctMgr.hasLinkedAccount()) 
    {
      hasDropboxLink = true;
          dropboxAcct = dropboxAcctMgr.getLinkedAccount();
    }
    
    
    //import the sample data if there is no new data
    try
    {
      setupSample();
    }
    catch(Exception e){
      Log.v("password", "failed to import sample");
    }
    
    //if the app is just starting, bring up the first screen
    if (savedInstanceState == null) 
    {
      selectFileFragment = null;
      createFileFragment = null;
      viewFileFragment = null;
      viewDetailFragment = null;
      importFileFragment = null;
      
      selectFileFragment = new SelectFileFragment();
      getSupportFragmentManager().beginTransaction().add(R.id.container, selectFileFragment).commit();
    }
    else
    {
      if (savedInstanceState.containsKey("document"))
      {
        String doc = savedInstanceState.getString("document");
        String name = savedInstanceState.getString("name");
        password = savedInstanceState.getString("password");
        currentDoc = savedInstanceState.getString("file");
        document = new PasswordDocumentFile(this, name, password);
        document.fromString(doc, false);
      }
      
      if (savedInstanceState.containsKey("details"))
      {
        String detStr = savedInstanceState.getString("details");
        details = new PasswordDetails();
        details.fromString(detStr);
      }
    }
  }

  
  
  public void fragmentExists(Fragment frag)
  {
    if (frag instanceof ViewDetailFragment)
      viewDetailFragment = (ViewDetailFragment) frag;
    else if (frag instanceof ViewFileFragment)
      viewFileFragment = (ViewFileFragment) frag;
    else if (frag instanceof SelectFileFragment)
      selectFileFragment = (SelectFileFragment) frag;
    else if (frag instanceof ImportFileFragment)
      importFileFragment = (ImportFileFragment) frag;
    else if (frag instanceof CreateFileFragment)
      createFileFragment = (CreateFileFragment) frag;
  }
  
  /**
   * if the data directory is empty, populate it with the provided sample file
   */
  private void setupSample() throws IOException
  {
    String path = getFilesDir().getAbsolutePath() + "/saved/";
    File fpath = new File(path);
    
    if (!fpath.exists())
      fpath.mkdirs();
    
    if (fpath.list().length > 0)
      return;
    
    path += "password is sample";
    File f = new File(path);
    
    if (f.exists())
      return;
    
    InputStream ins = getAssets().open("sample");
    PasswordDocument doc = new PasswordDocumentFile(this, "password is sample");
    doc.importFromStream(ins);
    doc.setPassword("sample");
    doc.save();
  }
  
  /** Keep track of the editable state of this Activity */ private boolean editable = false;
  
  /**
   * Sets the editable mode for this Activity.
   * Most of the views in this Activity have two states:  editable and viewable.
   * It works to pass on the editable information to the fragments whenever it gets set.
   * @param editable set true to set all fragments to editable mode
   */
  public void setEditable(boolean editable)
  {
    this.editable = editable;
    
    if (selectFileFragment != null)
      selectFileFragment.setEditable(editable);
    if (viewFileFragment != null)
      viewFileFragment.setEditable(editable);
    if (viewDetailFragment != null)
      viewDetailFragment.setEditable(editable);
  }
  
  /**
   * Get the current editable state.
   */
  public boolean getEditable()
  {
    return editable;
  }
  
  /**
   * Handle the behaviour of the back button.
   */
  @Override
  public void onBackPressed()
  {
    FragmentManager mgr = getSupportFragmentManager();
    int cnt = mgr.getBackStackEntryCount();
    
    if (cnt > 0)
    {
      BackStackEntry entry = mgr.getBackStackEntryAt(cnt - 1);
      String name = entry.getName();
      
      //warn any fragments that care that the back button has been pressed.
      //if they return true then cancel the back button action
      boolean keepGoing = true;
      
      if (name.equals(ViewDetailFragment.getName()))
      {
        keepGoing = viewDetailFragment.backPressed();
      }
      
      if (!keepGoing)
        return;
      
      //reset the view every time a fragment is popped off the stack
      super.onBackPressed();
      invalidateOptionsMenu();
      setEditable(false);
    }
  };
  
  /** 
   * The current document containing passwords.  
   * Fragments should refer to this variable to determine what data to display.
   */
  public PasswordDocument document;
  /** The password of the currently loaded password document. */ public String password;
  /** The filename of the currently loaded password document. */ public String currentDoc;
  
  /**
   * Prompt the user for a password to open the specified file.
   * Proceed to openFile2 if the password is correct.
   * @param file the name of the file in the filesystem to decode.
   */
  public void openFile(final PasswordDocument doc)
  {
    final MainActivity that = this;
    currentDoc = doc.name;
    
    //create an okay/cancel password dialog to get the document password
    PasswordFragment inDialog = new PasswordFragment("Input the document password", "password", new PasswordFragment.Listener() 
    {
      //attempt to decode the file with the provided password
      public boolean okay(String password) 
      {
        document = doc;
        doc.setPassword(password);
        boolean passed = document.testPassword();
        
        //display an error of failure
        if (!passed)
        {
          AlertFragment frag = new AlertFragment("Incorrect password.");
          frag.show(that.getSupportFragmentManager(), "invalid_fragment");
          return false;
        }
        //move on to actually opening the file otherwise
        else
        {
          that.password = password;
          openFile2();
          return true;
        }
      }
      
      //do nothing on cancel
      public void cancel() 
      {
      }
    });
    inDialog.show(that.getSupportFragmentManager(), "invalid_fragment");
  }
  
  /**
   * Load the specified file into memory.
   * @param file the name of the file to load in the filesystem.
   * @param password the password used to decrypt the file.
   */
  private void openFile2()
  {
    try
    {
      document.load(true);
      
      //open the file viewer fragment
      FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
      viewFileFragment = new ViewFileFragment();
      
      //if this is a new file, it will be empty
      //give it one sample entry for user ease
      if (document.details.size() == 0)
      {
        PasswordDetails det = new PasswordDetails();
        det.name = "new entry";
        document.setIndex(det);
        document.details.add(det);
      }
      
      //make the entries clickable on first view
      setEditable(false);
      
      viewFileFragment.setDocument(document);
      
      //setup the back button
      trans.replace(R.id.container, viewFileFragment);
      trans.addToBackStack(ViewFileFragment.getName());
      trans.commit();
    }
    catch(Exception e){
      AlertFragment frag = new AlertFragment("Failed to open the document: " + document.name);
      frag.show(getSupportFragmentManager(), "invalid_fragment");
    }
  }
  
  public void setFile(String name, String password)
  {
    currentDoc = name;
    document = new PasswordDocumentFile(this, name, password);
    this.password = password;
    boolean passed = document.testPassword();
    
    //display an error of failure
    if (!passed)
      document = null;
    else
      document.load(true);
  }
  
  public void setDetails(String index)
  {
    int sz = document.details.size();
    for (int i = 0; i < sz; i++)
    {
      PasswordDetails dets = document.details.get(i);
      
      if (dets.index.equals(index))
      {
        details = dets;
        break;
      }
    }
  }
  
  /**
   * Open the fragment that allows the user to create a new document.
   * @param type Type can either be CreateFileFragment.TYPE_CREATE or CreateFileFragment.TYPE_IMPORT
   */
  public void addFile(int type)
  {
    if (!(type == CreateFileFragment.TYPE_CREATE || type == CreateFileFragment.TYPE_IMPORT || type == CreateFileFragment.TYPE_CREATE_DROPBOX))
      return;
      
    //open the create file fragment
    setEditable(false);
    FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
    createFileFragment = new CreateFileFragment();
    createFileFragment.settype(type);
    
    //setup the back button
    trans.replace(R.id.container, createFileFragment);
    trans.addToBackStack(CreateFileFragment.getName());
    trans.commit();
  }
  
  /**
   * Delete the specified file from the file system irrecoverably.
   * @param name the name of the file the delete.
   */
  public void removeFile()
  {
    document.delete();
  }
  
  /**
   * The currently loaded password details used by the ViewDetailFragment fragment.
   */
  private PasswordDetails details;
  
  public PasswordDetails getDetails()
  {
    return details;
  }
  
  /**
   * Open the specified detail into a new ViewDetailFragment
   * @param detail
   */
  public void openDetail(PasswordDetails detail)
  {
    details = detail;
    FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
    viewDetailFragment = new ViewDetailFragment();
    
    //if the detail has no data, give it a sample to ease the user experience
    //make it editable as well.
    if (details.name.isEmpty() || (details.name.equals("new entry") && details.location.isEmpty() && details.details.size() == 0))
    {
      if (details.details.size() == 0)
      {
        details.details.add(new PasswordDetails.Pair());
        setEditable(true);
      }
    }
    else
      setEditable(false);
    
    //setup the back button
    viewDetailFragment.setDetails(details);
    trans.replace(R.id.container, viewDetailFragment);
    trans.addToBackStack(ViewDetailFragment.getName());
    trans.commit();
  }
  
  /**
   * Save the modified details to the opened password document
   * @param detail
   */
  public void saveDetail(PasswordDetails detail)
  {
    int listIdx = -1;
    int sz = document.details.size();
    for (int i = 0; i < sz; i++)
    {
      PasswordDetails d = document.details.get(i);
      if (d.index == detail.index)
      {
        listIdx = i;
        break;
      }
    }
    
    if (listIdx == -1)
      return;
    
    document.details.remove(listIdx);
    document.details.add(listIdx, detail);
    
    document.save();
  }
  
  /**
   * Bring up the import Fragment to select a file to import
   */
  public void openImportFile()
  {
    FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
    importFileFragment = new ImportFileFragment();
    
    File sdcardDir = Environment.getExternalStorageDirectory();
    importFileFragment.setDirectory(sdcardDir.getAbsolutePath());
    
    trans.replace(R.id.container, importFileFragment);
    trans.addToBackStack(ImportFileFragment.getName());
    trans.commit();
  }
  
  /**
   * Attempt to import the selected file.
   * @param path
   */
  public void importFile(String path)
  {
    try
    {
      document = new PasswordDocumentFile(this, path);
      document.importFromFile(path);
      
      onBackPressed();
      
      addFile(CreateFileFragment.TYPE_IMPORT);
    }
    catch(Exception e){
      AlertFragment inDialog = new AlertFragment("Unable to import file: " + path);
      inDialog.show(getSupportFragmentManager(), "invalid_fragment");
      return;
    }
  }
  
  public boolean hasDropbox()
  {
    return hasDropboxLink;
  }
  
  public DbxAccountManager getDropboxManager()
  {
    return dropboxAcctMgr;
  }
  
  public DbxAccount getDropboxAccount()
  {
    return dropboxAcct;
  }
  
  public void startDropbox()
  {
    dropboxAcctMgr.startLink(this, 1);
  }
  
  public static interface dropboxListener
  {
    public void connected();
  }
  
  private ArrayList<dropboxListener> dblisteners = new ArrayList<dropboxListener>();
  
  public void addDropboxListener(dropboxListener listener)
  {
    if (dblisteners.contains(listener))
      return;
    
    dblisteners.add(listener);
  }
  
  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) 
  {
      if (requestCode == 1) 
      {
          if (resultCode == Activity.RESULT_OK) 
          {
              dropboxAcct = dropboxAcctMgr.getLinkedAccount();
              hasDropboxLink = true;
              
              int sz = dblisteners.size();
              for (int i = 0; i < sz; i++)
              {
                dropboxListener l = dblisteners.get(i);
                l.connected();
              }
          } 
          else 
          {
            
          }
      } 
      else 
      {
          super.onActivityResult(requestCode, resultCode, data);
      }
  }
  
  public void about()
  {
    //open the file viewer fragment
    FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
    AboutFragment frag = new AboutFragment();
    
    //setup the back button
    trans.replace(R.id.container, frag);
    trans.addToBackStack(AboutFragment.getName());
    trans.commit();
  }
}




Java Source Code List

com.munger.passwordkeeper.MainActivity.java
com.munger.passwordkeeper.SplashScreen.java
com.munger.passwordkeeper.alert.AlertFragment.java
com.munger.passwordkeeper.alert.ConfirmFragment.java
com.munger.passwordkeeper.alert.InputFragment.java
com.munger.passwordkeeper.alert.PasswordFragment.java
com.munger.passwordkeeper.struct.AES256.java
com.munger.passwordkeeper.struct.PasswordDetails.java
com.munger.passwordkeeper.struct.PasswordDocumentDropbox.java
com.munger.passwordkeeper.struct.PasswordDocumentFile.java
com.munger.passwordkeeper.struct.PasswordDocument.java
com.munger.passwordkeeper.view.AboutFragment.java
com.munger.passwordkeeper.view.CreateFileFragment.java
com.munger.passwordkeeper.view.ImportFileFragment.java
com.munger.passwordkeeper.view.SelectFileFragment.java
com.munger.passwordkeeper.view.ViewDetailFragment.java
com.munger.passwordkeeper.view.ViewFileFragment.java
com.munger.passwordkeeper.view.widget.DetailItemWidget.java
com.munger.passwordkeeper.view.widget.FileItemWidget.java
com.munger.passwordkeeper.view.widget.TextInputWidget.java
com.munger.passwordkeeper.view.widget.TextWidget.java