// Copyright (c) 2009, Google Inc.
//
// 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 net.tawacentral.roger.secrets;
import net.tawacentral.roger.secrets.Secret.LogEntry;
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.ArrayAdapter;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* This activity displays the access log for a given secret. The access log
* records when a given action, such as creation, view, or modification, was
* performed on the secret. The log is shown in reverse chronological order.
*
* @author rogerta
*/
public class AccessLogActivity extends ListActivity {
/** Tag for logging purposes. */
public static final String LOG_TAG = "AccessLogActivity";
private static final long ONE_MINUTE_IN_SECS = 60;
private static final long ONE_HOUR_IN_SECS = 3600;
// This activity will only allow it self to be resumed in specific
// circumstances, so that leaving the application will force the user to
// re-enter the master password. Older versions used to check the state of
// the keyguard, but this check is no longer reliable with Android 4.1.
private boolean allowNextResume; // Allow the next onResume()
/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Secret secret = (Secret) getIntent().getExtras().getSerializable(
SecretsListActivity.EXTRA_ACCESS_LOG);
// Set the title of the activity to be the description of the secret.
String pattern = getText(R.string.log_name_format).toString();
setTitle(MessageFormat.format(pattern, secret.getDescription()));
// Create an array of strings from the access log.
List<Secret.LogEntry> accessLog = secret.getAccessLog();
ArrayList<String> strings = new ArrayList<String>(accessLog.size());
for (Secret.LogEntry entry : accessLog) {
String s = getElapsedString(this, entry, 0);
strings.add(s);
}
setListAdapter(new ArrayAdapter<String>(this, R.layout.access_log,
strings));
allowNextResume = true;
}
@Override
protected void onResume() {
super.onResume();
// Don't allow this activity to continue if it has not been explicitly
// allowed.
if (!allowNextResume) {
Log.d(LOG_TAG, "onResume not allowed");
finish();
return;
}
allowNextResume = false;
}
/**
* Trap the "back" button to signal to the parent activity that the user
* pressed back and therefore should be allowed to resume. This activity
* has no other user interaction, so leave the activity in any other way
* should cause the parent to not resume.
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.KEYCODE_BACK == keyCode)
setResult(RESULT_OK);
return super.onKeyDown(keyCode, event);
}
/**
* Formats a string that represents the elapsed time since the log entry
* was created and the time specified by the now argument. If now is
* zero, then the current time will be used.
*
* The string is formatted differently depending on how much time has
* elapsed. For example, strings can take the form "? seconds ago",
* "today at ?", or "{date} {time}".
*
* @param context Activity context used for getting string resources.
* @param entry Log entry whose elapsed time we want to show.
* @param now End time to use for elapsed duration. May be zero, in which
* case the current time is used.
* @return String representing elapsed time.
*/
public static String getElapsedString(Context context, LogEntry entry,
long now) {
Calendar c = Calendar.getInstance();
// If a time for now is not specified, get the current time.
if (0 == now)
now = c.getTimeInMillis();
else
c.setTimeInMillis(now);
// Calculate two msecs: one for the start of today and another for the
// start of yesterday.
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
long midnight = c.getTimeInMillis();
c.add(Calendar.DAY_OF_YEAR, -1);
long yesterdayMidnight = c.getTimeInMillis();
long time = entry.getTime();
long diff = (now - time) / 1000;
String verb;
switch(entry.getType()) {
case LogEntry.CREATED:
verb = context.getText(R.string.log_created).toString();
break;
case LogEntry.CHANGED:
verb = context.getText(R.string.log_changed).toString();
break;
case LogEntry.VIEWED:
verb = context.getText(R.string.log_viewed).toString();
break;
case LogEntry.EXPORTED:
verb = context.getText(R.string.log_exported).toString();
break;
case LogEntry.SYNCED:
verb = context.getText(R.string.log_synced).toString();
break;
default:
// Should never really get here.
verb = "?";
}
String s;
if (diff < ONE_MINUTE_IN_SECS) {
String pattern = context.getText(R.string.log_sec).toString();
s = MessageFormat.format(pattern, verb);
} else if (diff < ONE_HOUR_IN_SECS) {
String pattern = context.getText(R.string.log_min).toString();
s = MessageFormat.format(pattern, verb, diff / 60);
} else {
String pattern;
if (time > midnight) {
pattern = context.getText(R.string.log_today).toString();
} else if (time > yesterdayMidnight) {
pattern = context.getText(R.string.log_yesterday).toString();
} else {
pattern = context.getText(R.string.log_date).toString();
}
s = MessageFormat.format(pattern, verb, new Date(time));
}
return s;
}
}