package com.androidron.keyring;
/*
Keyring for Android
Copyright (C) 2011 Ron Riley
(android.keyring@gmail.com)
Keyring for Android is based on:
KeyringEditor
Copyright 2004 Markus Griessnig
Vienna University of Technology
Institute of Computer Technology
KeyringEditor is based on:
Java Keyring v0.6
Copyright 2004 Frank Taylor <keyring@lieder.me.uk>
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import keyring.Model;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
public abstract class RootListActivity extends ListActivity {
public static final String KEYSTORE_FILENAME = "keyStore.pdb";
private static final String TAG = "RootListActivity";
protected PdbFileHandlerService fileService;
protected boolean serviceIsBound = false;
protected boolean serviceIsReady = false;
// these to recover after orientation change pita
protected Dialog passwordDialog;
protected Dialog otherDialog;
protected Intent passwordDialogIntent;
protected DialogStore dialogStore;
private ScreenOrientationHandler screenOrientationHandler;
private void challengeForPassword(final Intent intent) {
if (fileService.passwordSet()) {
//finish();
startActivity(intent);
} else {
final Dialog dialog = new PasswordDialog(RootListActivity.this);
passwordDialog = dialog;
passwordDialogIntent = intent;
dialog.setContentView(R.layout.password_dialog);
dialog.setTitle(R.string.password);
final EditText password = (EditText) dialog
.findViewById(R.id.password);
final TextView message = (TextView) dialog
.findViewById(R.id.message);
Button buttonPassword = (Button) dialog.findViewById(R.id.button);
Button buttonCancel = (Button) dialog
.findViewById(R.id.button_cancel);
buttonCancel.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
dialog.dismiss();
}
});
buttonPassword.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
fileService.setPassword(password.getText().toString()
.toCharArray());
dialog.dismiss();
//finish();
startActivity(intent);
} catch (BadPasswordException pwd) {
password.setText("");
message.setText(R.string.label_failed_password);
}
}
});
onCreateDialog(R.layout.password_dialog);
dialog.show();
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
fileService = ((PdbFileHandlerService.LocalBinder) service)
.getService();
serviceIsReady = true;
onServiceReady();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
fileService = null;
serviceIsReady = false;
}
};
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
Intent intent = new Intent();
switch (item.getItemId()) {
case R.id.import_pdb:
intent.setClassName("com.androidron.keyring", "com.androidron.keyring.ImportPdb");
if (fileService.hasPrivateKeystore()) {
challengeForPassword(intent);
} else if (!fileService.hasPrivateKeystore()) {
finish();
startActivity(intent);
}
return true;
case R.id.export_pdb:
intent.setClassName("com.androidron.keyring", "com.androidron.keyring.ExportPdb");
challengeForPassword(intent);
return true;
case R.id.category_editor:
intent.setClassName("com.androidron.keyring",
"com.androidron.keyring.CategoryEditor");
finish();
startActivity(intent);
return true;
case R.id.password_timeout:
intent.setClassName("com.androidron.keyring",
"com.androidron.keyring.PasswordTimeout");
challengeForPassword(intent);
return true;
case R.id.password:
intent.setClassName("com.androidron.keyring",
"com.androidron.keyring.PasswordChanger");
challengeForPassword(intent);
return true;
case R.id.help:
intent.setClassName("com.androidron.keyring",
"com.androidron.keyring.Help");
startActivity(intent);
return true;
case R.id.new_pdb:
intent.setClassName("com.androidron.keyring", "com.androidron.keyring.NewPrivateKeystore");
if (fileService.hasPrivateKeystore()) {
challengeForPassword(intent);
} else if (!fileService.hasPrivateKeystore()) {
startActivity(intent);
}
return true;
case R.id.toggle_orientation:
intent.setClassName("com.androidron.keyring", "com.androidron.keyring.ScreenOrientationHandlerActivity");
startActivity(intent);
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
Intent service = new Intent();
service.setClassName("com.androidron.keyring",
"com.androidron.keyring.PdbFileHandlerService");
startService(service); // kick off a persistent service if not already running
bindService(service, mConnection, Context.BIND_AUTO_CREATE); // bind to it
serviceIsBound = true;
}
void doUnbindService() {
if (serviceIsBound) {
// Detach our existing connection.
unbindService(mConnection);
}
serviceIsBound = false;
}
@Override
protected void onDestroy() {
super.onDestroy();
// doUnbindService();
}
protected void onServiceReady(){
if (dialogStore != null){
challengeForPassword(dialogStore.getDialogIntent());
}
}
protected void setUpActionBar() {
final Intent intent = new Intent();
ImageButton homeButton = (ImageButton) findViewById(R.id.go_home);
homeButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
intent.setClassName("com.androidron.keyring",
"com.androidron.keyring.IndexList");
//finish();
startActivity(intent);
}
});
ImageButton addButton = (ImageButton) findViewById(R.id.go_add);
addButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
intent.setClassName("com.androidron.keyring", "com.androidron.keyring.Item");
intent.putExtra("entry.id", -1);
challengeForPassword(intent);
}
});
ImageButton searchButton = (ImageButton) findViewById(R.id.go_search);
searchButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
onSearchRequested();
}
});
}
// TODO move this and RootActivity builders to utility class
protected AlertDialog.Builder buildCancel(AlertDialog.Builder builder,
int message) {
builder.setMessage(message)
// TODO lookup
.setCancelable(true)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
return builder;
}
// TODO refactor out and have a static to keep a note of
// whether they have been warned
private void checkCharSet(){
// palm os uses Windows-1252 charset
// check charsets
try{
java.nio.charset.Charset cs = Charset.forName(Model.PALM_CHARSET);
}
catch (UnsupportedCharsetException noPalmCs){
AlertDialog.Builder builder = new AlertDialog.Builder(
RootListActivity.this);
builder = buildCancel(builder,
R.string.warn_unsupported_charset);
//builder.create();
otherDialog = builder.show();
return;
}
}
// public Object onRetainNonConfigurationInstance() {
// return fileService;
//}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
if (passwordDialog != null){
savedInstanceState.putBoolean("showPasswordDialog", true);
savedInstanceState.putParcelable("passwordDialogIntent", passwordDialogIntent);
}
//fileService = null;
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
if (savedInstanceState.getBoolean("showPasswordDialog")){
Log.d(TAG,"invoking challenge for password");
Log.d(TAG,"intent is: " + (Intent)savedInstanceState.getParcelable("passwordDialogIntent"));
dialogStore = new DialogStore((Intent)savedInstanceState.getParcelable("passwordDialogIntent"),"PasswordDialog");
}
}
@Override
public void onPause(){
super.onPause();
if (passwordDialog != null){
passwordDialog.dismiss(); // keep track of dialogs and dismiss them, imho Android should do this
}
if (otherDialog != null){
otherDialog.dismiss(); // keep track of dialogs and dismiss them, imho Android should do this
}
}
public void onStop(){
doUnbindService();
super.onStop();
}
public void onStart(){
super.onStart();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
//if (ScreenOrientationHandler.newOrientation()){
setRequestedOrientation(ScreenOrientationHandler.getScreenOrientation(getApplicationContext()));
//}
this.setUpActionBar();
checkCharSet();
doBindService();
super.onCreate(savedInstanceState);
}
}
|