Java tutorial
package com.etime; /* * This file is part of ETime. * * ETime 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. * * ETime 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 ETime. If not, see <http://www.gnu.org/licenses/>. */ import android.app.*; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import org.apache.http.HttpVersion; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.params.HttpClientParams; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnManagerPNames; import org.apache.http.conn.params.ConnPerRouteBean; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import java.util.Calendar; import java.util.List; public class ETimeActivity extends Activity { final Activity activity = this; private String TAG = "ETime-4321"; /* used to handle the auto clock out alarm */ private AlarmManager am; private PendingIntent pendingIntentAutoClockAlarm; private String PREFS_USERNAME = "username"; private String PREFS_PASSWORD = "password"; private DefaultHttpClient httpClient; protected String loginName = null; protected String password = null; private long loginTime; //Used to determine if loginTime is expired private static final long DEF_TIMEOUT = 900000; // 15 mins in milliseconds private ProgressBar progressBar; //the loading progress bar used during login process private ProgressBar progressBar2; //spinning bar to be used when loading timecard data private TextView loading; private List<Punch> punches; // list of punches in/out for today private double totalHrs; // total hrs logged today, not counting time since last punch in private String oldLoginNameBeforePreferencePage; private Button recordTime; //Record time stamp button private Button curStatus; //A print out of the last punch private Button textViewTotalHrs; //Total hours logged this pay period private Button totalHrsLoggedToday; //Total hours logged today private Button timeToClockOut; //Eight hour clock out time. private boolean AUTO_CLOCKOUT; private NotificationManager mManager; //Notification used for showing auto clock out time private static final int APP_ID = 1; //APP id used in notifications, also used in TimeAlarmService. DO NOT CHANGE private String lastNotificationMessage; //Used to limit notifications to only updated notifications private boolean notCreated = true; // onResume not run yet private boolean oldAutoClockBeforePreferencePage; //Used to check if auto clock settings has been changed @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); } /** * Called when the activity is resumed from sleep. Called during onCreate. * Checks if the preferences are valid (password and username are * non-empty). If empty, preferences activty is brought up, other wise * title page is setup. * * {@inheritDoc} */ @Override public void onResume() { super.onResume(); if (validConfig()) { setupTitlePage(); } else { /* show config page, to set username password */ Toast.makeText(getApplicationContext(), "Username/Password required", Toast.LENGTH_LONG).show(); startPreferencesPage(); } } @Override public void onDestroy() { super.onDestroy(); if (mManager != null) mManager.cancel(APP_ID); } /** * Notify the user with the message "message". Notification is set to * on-going, on-going is needed to tell android not to kill the app. * The phone with vibrate, and light up on notification. If the message * is the exact same message as the last message notified then the * notification is not set again. * @param message Message to notify user with */ protected void notify(String message) { if (message.equalsIgnoreCase(lastNotificationMessage)) { return; } else { lastNotificationMessage = message; } int icon = R.drawable.icon; long when = System.currentTimeMillis(); Context context = getApplicationContext(); CharSequence contentTitle = "ETime"; Intent notificationIntent = new Intent(this, ETimeActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Notification notification = new Notification(icon, message, when); notification.flags |= Notification.DEFAULT_LIGHTS; notification.flags |= Notification.FLAG_ONGOING_EVENT; notification.setLatestEventInfo(context, contentTitle, message, contentIntent); mManager.notify("ETime", APP_ID, notification); } /** * Start the preferences page */ protected void startPreferencesPage() { oldLoginNameBeforePreferencePage = loginName; oldAutoClockBeforePreferencePage = AUTO_CLOCKOUT; startActivity(new Intent(activity, ETimePreferences.class)); } /** * Set punches * @param punches List of punches of all of today's punch in/out's */ public void setPunches(List<Punch> punches) { this.punches = punches; } /** * Set total hrs logged today, does not include time since last clock in * @param totalHrs total hrs logged today, does not include time since last clock in */ public void setTotalHrs(double totalHrs) { this.totalHrs = totalHrs; } /** * Called when TimeCardAsyncTask is done processing. Does lot of stuff. */ public void onPostParsingTimeCard() { Log.v(TAG, "in postParingTimeCard"); textViewTotalHrs.setText("Total Hrs this pay period: " + totalHrs); totalHrsLoggedToday.setText("Total Hrs Today: " + ETimeUtils.todaysTotalHrsLogged(punches)); Punch lastPunch; if (punches.size() > 0) { lastPunch = punches.get(punches.size() - 1); if (lastPunch != null) { updateCurStatusBtn(); Punch eightHrPunch = ETimeUtils.getEightHrPunch(punches); Calendar eightHrPunchCalendar = eightHrPunch.getCalendar(); updateTimeToClockOut(eightHrPunchCalendar); setAutoClockOut(eightHrPunch); } } progressBar2.setVisibility(View.GONE); } /** * Update the curStatus button with most recent data from the users * time card. */ private void updateCurStatusBtn() { StringBuilder sb = new StringBuilder("Clocked "); Punch lastPunch; Calendar lastPunchCalendar; int minute; if (punches.isEmpty()) { return; } lastPunch = punches.get(punches.size() - 1); if (lastPunch.isClockIn()) { sb.append("in "); } else { sb.append("out "); } sb.append("at "); lastPunchCalendar = lastPunch.getCalendar(); sb.append(Integer.toString(getHourFromCalendar(lastPunchCalendar))).append(":"); minute = lastPunch.getCalendar().get(Calendar.MINUTE); if (minute < 10) { sb.append("0"); } sb.append(Integer.toString(minute)); if (lastPunchCalendar.get(Calendar.AM_PM) == Calendar.AM) { sb.append(" AM"); } else { sb.append(" PM"); } curStatus.setText(sb.toString()); } /** * set the alarm so auto clock occurs at the time specified * by eightHrPunch. * @param eightHrPunch Is an identical Punch instance to * what the punch would be if the user * clocked out at exactly 8 hrs. */ private void setAutoClockOut(Punch eightHrPunch) { Punch lastPunch; if (AUTO_CLOCKOUT) { if (punches.isEmpty()) { return; } lastPunch = punches.get(punches.size() - 1); long countDownTime = eightHrPunch.getCalendar().getTimeInMillis() - Calendar.getInstance().getTimeInMillis(); if (countDownTime > 0 && lastPunch.isClockIn()) { setOneTimeAlarm(eightHrPunch.getCalendar().getTimeInMillis()); ETimeActivity.this.notify("Auto clock out at: " + punchToTimeString(eightHrPunch)); } } } /** * Converts a punch to a human readable time format * "12:00 AM" * @param punch Punch to convert to readable string * @return A string conversion of a Punch in a readable format */ public String punchToTimeString(Punch punch) { Calendar calendar = punch.getCalendar(); int hour = getHourFromCalendar(calendar); int minute = calendar.get(Calendar.MINUTE); String minStr = (minute < 10) ? "0" + minute : "" + minute; return " " + hour + ":" + minStr + " " + ((calendar.get(Calendar.AM_PM) == Calendar.AM) ? "AM" : "PM"); } /** * Update the button timeToClockOut * @param eightHrPunchCalendar A calendar object specifying the time where * the user has been punched in for exactly 8 hrs * today. */ private void updateTimeToClockOut(Calendar eightHrPunchCalendar) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Clock out at "); StringBuilder clockTimeString = new StringBuilder(); clockTimeString.append(Integer.toString(getHourFromCalendar(eightHrPunchCalendar))).append(":"); int min = eightHrPunchCalendar.get(Calendar.MINUTE); if (min < 10) { clockTimeString.append("0"); } clockTimeString.append(Integer.toString(min)); if (eightHrPunchCalendar.get(Calendar.AM_PM) == Calendar.AM) { clockTimeString.append(" AM"); } else { clockTimeString.append(" PM"); } stringBuilder.append(clockTimeString); timeToClockOut.setText(stringBuilder.toString()); } /** * Get the hour of day in am/pm from a Calendar time * @param calendar Calendar with the hour you want to convert * @return The hour in am/pm format from HOUR_OF_DAY in Calendar which * ranges from 0-23 */ private int getHourFromCalendar(Calendar calendar) { int hour24 = calendar.get(Calendar.HOUR_OF_DAY); if (hour24 == 0) //12 AM { return 12; } else if (hour24 > 12) { return (hour24 - 12); } else { return hour24; } } /** * Run after LoginAsyncTask finishes. Record the time this function * is run for loginTime. */ public void onPostLogin() { hideProgressBar(); loginTime = Calendar.getInstance().getTimeInMillis(); showTitlePageBtns(); parseTimeCard(); } /** * setup global variables, only called on the first call to onResume */ private void setupGlobals() { loginTime = 0; httpClient = setupHttpClient(); progressBar = (ProgressBar) findViewById(R.id.pb_progressBar); progressBar2 = (ProgressBar) findViewById(R.id.progressBar2); recordTime = (Button) findViewById(R.id.btn_recordTime); textViewTotalHrs = (Button) findViewById(R.id.btn_totalHrs); totalHrsLoggedToday = (Button) findViewById(R.id.btn_totalHrsToday); curStatus = (Button) findViewById(R.id.btn_curStatus); loading = (TextView) findViewById(R.id.tv_load); timeToClockOut = (Button) findViewById(R.id.btn_timeToClockOut); } private DefaultHttpClient setupHttpClient() { SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); HttpParams params = new BasicHttpParams(); params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpClientParams.setRedirecting(params, false); ClientConnectionManager cm = new SingleClientConnManager(params, schemeRegistry); return (new DefaultHttpClient(cm, params)); } /** * setup the ui title page. On the first time run, setup global variables * and buttons. */ private void setupTitlePage() { if (notCreated) { setContentView(R.layout.title_page); setupGlobals(); setupButtons(); notCreated = false; } login(); } /** * login - sets the title of the app to "ETime - username". Hides the progress bar and * shows the title page including the text and buttons. Logs in into the main adp site * and saves the relevant cookies in httpclient. * * If login has happened in the last 15 mins, don't re-login. */ private void login() { long curTime = System.currentTimeMillis(); setTitle("ETime - " + loginName); if (((curTime - loginTime) > DEF_TIMEOUT) || !oldLoginNameBeforePreferencePage.equals(loginName)) { oldLoginNameBeforePreferencePage = loginName; LoginAsyncTask loginAsyncTask = new LoginAsyncTask(); progressBar.setProgress(0); httpClient.getCredentialsProvider().setCredentials(new AuthScope(null, -1), new UsernamePasswordCredentials(loginName, password)); loginAsyncTask.setProgressBar(progressBar); loginAsyncTask.setActivity(this); loginAsyncTask.setHttpClient(httpClient); loginAsyncTask.setContext(getApplicationContext()); loginAsyncTask.execute(); if (progressBar.getVisibility() == View.GONE) { progressBar2.setVisibility(View.VISIBLE); } } else { hideProgressBar(); showTitlePageBtns(); if (AUTO_CLOCKOUT != oldAutoClockBeforePreferencePage) { parseTimeCard(); } } oldAutoClockBeforePreferencePage = AUTO_CLOCKOUT; } /** * setup the buttons on the title page (e.g. setup the record timestamp * button to clockOut() when pressed. */ private void setupButtons() { recordTime.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { clockOut(); } }); } /** * start the time card activity */ protected void startTimeCardActivity() { Intent intent = new Intent(activity, TimeCardActivity.class); intent.putExtra("loginName", loginName); intent.putExtra("password", password); startActivity(intent); } /** * parse the timecard of the user. Starts a TimeCardAsyncTask */ protected void parseTimeCard() { progressBar2.setVisibility(View.VISIBLE); TimeCardAsyncTask timeCardAsyncTask = new TimeCardAsyncTask(); timeCardAsyncTask.setActivity((ETimeActivity) activity); timeCardAsyncTask.setHttpClient(httpClient); timeCardAsyncTask.setProgressBar(progressBar); timeCardAsyncTask.execute(); } /** * Hide title page buttons and text. */ protected void hideTitlePageBtns() { recordTime.setVisibility(View.GONE); curStatus.setVisibility(View.GONE); textViewTotalHrs.setVisibility(View.GONE); totalHrsLoggedToday.setVisibility(View.GONE); timeToClockOut.setVisibility(View.GONE); } /** * Show title page buttons and text. */ protected void showTitlePageBtns() { recordTime.setVisibility(View.VISIBLE); curStatus.setVisibility(View.VISIBLE); textViewTotalHrs.setVisibility(View.VISIBLE); totalHrsLoggedToday.setVisibility(View.VISIBLE); timeToClockOut.setVisibility(View.VISIBLE); } /** * Hide progress bar and text. */ protected void hideProgressBar() { progressBar.setVisibility(View.GONE); loading.setVisibility(View.GONE); } /** * Show progress bar and text. */ protected void showProgressBar() { progressBar.setVisibility(View.VISIBLE); loading.setVisibility(View.VISIBLE); } /** * Return if the username and password is non-empty. * This method also has the side effect of settting the loginName, * password, and autoclock. * @return return true if loginName an password are non-empty, false otherwise. */ private boolean validConfig() { SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(activity); loginName = pref.getString(PREFS_USERNAME, null); password = pref.getString(PREFS_PASSWORD, null); AUTO_CLOCKOUT = pref.getBoolean(getString(R.string.autoclock), false); if (AUTO_CLOCKOUT != oldAutoClockBeforePreferencePage && !AUTO_CLOCKOUT) { if (pendingIntentAutoClockAlarm != null) { am.cancel(pendingIntentAutoClockAlarm); pendingIntentAutoClockAlarm = null; } ETimeActivity.this.notify("Auto clock out cancelled!"); } return (loginName != null && !loginName.equals("")) && (password != null && !password.equals("")); } /** * Load the timestamp page in webview */ private void clockOut() { hideTitlePageBtns(); showProgressBar(); TimestampAsyncTask timestampAsyncTask = new TimestampAsyncTask(); timestampAsyncTask.setActivity((ETimeActivity) activity); timestampAsyncTask.setHttpClient(httpClient); timestampAsyncTask.setProgressBar(progressBar); timestampAsyncTask.execute(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_preferences: startPreferencesPage(); break; case R.id.menu_timecard: startTimeCardActivity(); break; case R.id.menu_refresh: loginTime = 0; progressBar2.setVisibility(View.VISIBLE); onResume(); break; } return true; } /** * Callback for pressing the back button. Used to prevent the app * from destroying it self if the back button is pressed to go to * previous app/homescreen. */ @Override public void onBackPressed() { SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(activity); if (pref.getBoolean(getString(R.string.keepInBackground), true)) { Intent setIntent = new Intent(Intent.ACTION_MAIN); setIntent.addCategory(Intent.CATEGORY_HOME); setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(setIntent); } else { super.onBackPressed(); } } /** * Set the alarm that will perform autoclock out at the specified time. * @param alarmTime time in milliseconds since epoch when the alarm * should run. */ public void setOneTimeAlarm(long alarmTime) { Intent intent = new Intent(this, TimeAlarm.class); intent.putExtra("username", loginName); intent.putExtra("password", password); pendingIntentAutoClockAlarm = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT); am.set(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntentAutoClockAlarm); } public void setLoginTime(long loginTime) { this.loginTime = loginTime; } }