Java tutorial
/** * ORcycle, Copyright 2014, 2015, PSU Transportation, Technology, and People Lab. * * @author Robin Murray <robin5@pdx.edu> (code) * @author Miguel Figliozzi <figliozzi@pdx.edu> and ORcycle team (general app * design and features, report questionnaires and new ORcycle features) * * For more information on the project, go to * http://www.pdx.edu/transportation-lab/orcycle and http://www.pdx.edu/transportation-lab/app-development * * Updated/modified for Oregon pilot study and app deployment. * * ORcycle 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 any later version. * ORcycle 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 * ORcycle. If not, see <http://www.gnu.org/licenses/>. * */ package edu.pdx.cecs.orcycle; import java.text.SimpleDateFormat; import java.util.List; import java.util.UUID; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.location.Location; import android.location.LocationManager; import android.os.Build; import android.os.IBinder; import android.support.v4.app.FragmentActivity; import android.util.Log; /** * This class extends the <code>Application<code/> class, and implements it as a singleton. * This class is used to maintain global application state. * @author robin5 (Robin Murray) * @version 1.0 * @see <code>Application<code/> class. * created 5/22/2014 */ public class MyApplication extends android.app.Application { private final String MODULE_TAG = "MyApplication"; public static final String PREFS_APPLICATION = "PREFS_APPLICATION"; public static final String ORCYCLE_URI = "http://www.pdx.edu/transportation-lab/android-instructions"; public static final String URI_PRIVACY_POLICY = "http://www.pdx.edu/transportation-lab/privacy-policy"; public static final String URI_REPORT_ROAD_HAZARDS = "http://www.pdx.edu/transportation-lab/reporting-road-hazards"; public static final String URI_ORCYCLE_MAPS = "http://www.pdx.edu/transportation-lab/orcycle-maps"; private static final String SETTING_USER_WELCOME_ENABLED = "USER_WELCOME_ENABLED"; private static final String SETTING_TUTORIAL_ENABLED = "TUTORIAL_ENABLED"; private static final String SETTING_USER_INFO_UPLOADED = "USER_INFO_UPLOADED"; private static final String SETTING_FIRST_TRIP_COMPLETED = "SETTING_FIRST_TRIP_COMPLETED"; private static final String SETTING_HINT_DONT_REPEAT_TRIPS = "SETTING_WARN_REPEAT_TRIPS"; private static final String SETTING_HINT_DO_REPORT_NOW = "SETTING_HINT_DO_REPORT_NOW"; private static final String SETTING_HINT_DO_REPORT_LATER = "SETTING_HINT_DO_REPORT_LATER"; private static final String SETTING_HINT_EMAIL_NAME_AND_NUMBER = "SETTING_HINT_EMAIL_NAME_AND_NUMBER"; private static final String SETTING_USER_ID = "SETTING_USER_ID"; private static final String SETTING_FIRST_USE = "SETTING_FIRST_USE"; private static final String SETTING_SIX_MONTH_ALARM_ENABLED = "SETTING_SIX_MONTH_ALARM_ENABLED"; private static final double RESET_START_TIME = 0.0; private static final String ANDROID_USER = "android"; private String userId = null; private int versionCode; private String versionName; private String appVersion; private String deviceModel; private long firstUse = -1; private boolean hintDontRepeatTrips; private boolean hintDoReportNow; private boolean hintDoReportLater; private boolean hintEmailNameAndNumber; private boolean firstTripCompleted; private boolean sixMonthAlarmEnabled; private RecordingService recordingService = null; private TripData trip; private boolean running; private boolean checkedForUserProfile = false; private boolean userProfileUploaded; private boolean checkedForUserWelcome = false; private boolean userWelcomeEnabled; private boolean checkedForTutorial = false; private boolean tutorialEnabled; private double lastTripStartTime = RESET_START_TIME; /** * Reference to class instance */ private static MyApplication myApp = null; private static final Controller controller = new Controller(); /** * Returns the class instance of the MyApplication object */ public static MyApplication getInstance() { return myApp; } public Controller getController() { return controller; } // ********************************************************************************* // * Application Interface // ********************************************************************************* /** * Called when the application is starting, before any activity, service, * or receiver objects (excluding content providers) have been created. * @throws java.lang.OutOfMemoryError */ @Override public final void onCreate() { super.onCreate(); // Set reference to this instance myApp = this; ConnectRecordingService(); loadApplicationSettings(); } private void loadApplicationSettings() { //generateUserId(); // For resetting while debugging SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); userId = settings.getString(SETTING_USER_ID, null); if ((null == userId) || (userId.equals(""))) { userId = generateUserId(); } firstUse = settings.getLong(SETTING_FIRST_USE, -1); if (-1 == firstUse) { firstUse = generateFirstUse(); } // setDefaultApplicationSettings(); firstTripCompleted = settings.getBoolean(SETTING_FIRST_TRIP_COMPLETED, true); userProfileUploaded = settings.getBoolean(SETTING_USER_INFO_UPLOADED, false); //userWelcomeEnabled = settings.getBoolean(SETTING_USER_WELCOME_ENABLED, true); // We are purposely disabling the welcome screen for now userWelcomeEnabled = false; tutorialEnabled = settings.getBoolean(SETTING_TUTORIAL_ENABLED, true); hintDontRepeatTrips = settings.getBoolean(SETTING_HINT_DONT_REPEAT_TRIPS, true); hintDoReportNow = settings.getBoolean(SETTING_HINT_DO_REPORT_NOW, true); hintDoReportLater = settings.getBoolean(SETTING_HINT_DO_REPORT_LATER, true); hintEmailNameAndNumber = settings.getBoolean(SETTING_HINT_EMAIL_NAME_AND_NUMBER, true); if (false == (sixMonthAlarmEnabled = settings.getBoolean(SETTING_SIX_MONTH_ALARM_ENABLED, false))) { UseReminder.rescheduleAlarm(this.getBaseContext()); setSixMonthAlarmEnabled(true); } loadDeviceInfo(); } public void setDefaultApplicationSettings() { //setFirstTripCompleted(true); // for debugging setFirstTripCompleted(false); setUserProfileUploaded(false); setUserWelcomeEnabled(false); setTutorialEnabled(true); setHintDontRepeatTrips(true); setHintDoReportNow(true); setHintDoReportLater(true); setHintEmailNameAndNumber(true); setSixMonthAlarmEnabled(false); } /** * This is called when the overall system is running low on memory, and * actively running processes should trim their memory usage. */ @Override public final void onLowMemory() { super.onLowMemory(); } /** * Called when the operating system has determined that it is a good * time for a process to trim unneeded memory from its process. */ @Override public final void onTrimMemory(int level) { super.onTrimMemory(level); } /** * Called by the system when the device configuration changes while * the component is running. */ @Override public final void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } // ********************************************************************************* // * // ********************************************************************************* public boolean isRunning() { return this.running; } public void setRunning(boolean value) { running = value; } // ********************************************************************************* // * // ********************************************************************************* private boolean isProviderEnabled() { final LocationManager manager = (LocationManager) getSystemService(LOCATION_SERVICE); return manager.isProviderEnabled(LocationManager.GPS_PROVIDER); } public ApplicationStatus getStatus() { ApplicationStatus applicationStatus = new ApplicationStatus(this.isProviderEnabled(), this.trip); return applicationStatus; } // ********************************************************************************* // * RecordingService ServiceConnection Interface // ********************************************************************************* /** * Connects the recording service to the Application object */ private void ConnectRecordingService() { try { Intent intent = new Intent(this, RecordingService.class); bindService(intent, recordingServiceServiceConnection, Context.BIND_AUTO_CREATE); } catch (SecurityException ex) { Log.d(MODULE_TAG, ex.getMessage()); } } /** * Connection to the RecordingService */ public final ServiceConnection recordingServiceServiceConnection = new ServiceConnection() { /** * Called when a connection to the Service has been established, with * the {@link android.os.IBinder} of the communication channel to the * Service. * * @param name The concrete component name of the service that has * been connected. * * @param service The IBinder of the Service's communication channel, * which you can now make calls on. */ public void onServiceConnected(ComponentName name, IBinder service) { Log.v(MODULE_TAG, "Connecting to RecordingService"); if (null == recordingService) { recordingService = ((RecordingService.MyServiceBinder) service).getService(); } } /** * Called when a connection to the Service has been lost. This typically * happens when the process hosting the service has crashed or been killed. * This does <em>not</em> remove the ServiceConnection itself -- this * binding to the service will remain active, and you will receive a call * to {@link #onServiceConnected} when the Service is next running. * * @param name The concrete component name of the service whose * connection has been lost. */ public void onServiceDisconnected(ComponentName name) { Log.v(MODULE_TAG, "Disconnecting from RecordingService"); recordingService = null; } }; public IRecordService getRecordingService() { return recordingService; } /** * startRecording */ public void startRecording(FragmentActivity activity) { switch (recordingService.getState()) { case RecordingService.STATE_IDLE: trip = TripData.createTrip(activity); recordingService.startRecording(trip); break; case RecordingService.STATE_RECORDING: long id = recordingService.getCurrentTripID(); trip = TripData.fetchTrip(activity, id); break; } startRecordingNotification(lastTripStartTime = trip.getStartTime()); UseReminder.rescheduleAlarm(activity); UseReminder.cancelOneWeekAlarm(activity); } /** * finishRecording */ public void finishRecording() { recordingService.finishRecording(); clearRecordingNotifications(); lastTripStartTime = RESET_START_TIME; } /** * cancelRecording */ public void cancelRecording() { recordingService.cancelRecording(); clearRecordingNotifications(); lastTripStartTime = RESET_START_TIME; } public boolean isRecording() { if (recordingService == null) { return false; } else { return ((RecordingService.STATE_RECORDING == recordingService.getState()) || (RecordingService.STATE_PAUSED == recordingService.getState())); } } // ********************************************************************************* // * UserProfile // ********************************************************************************* public void setCheckedForUserProfile(boolean value) { checkedForUserProfile = value; } public boolean getCheckedForUserProfile() { return checkedForUserProfile; } public void setUserProfileUploaded(boolean value) { userProfileUploaded = value; SharedPreferences settings; settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_USER_INFO_UPLOADED, userProfileUploaded); editor.apply(); } public boolean getUserProfileUploaded() { return userProfileUploaded; } public void setFirstTripCompleted(boolean value) { firstTripCompleted = value; SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_FIRST_TRIP_COMPLETED, firstTripCompleted); editor.apply(); } public boolean getFirstTripCompleted() { return firstTripCompleted; } // ********************************************************************************* // * UserWelcome // ********************************************************************************* public void setCheckedForUserWelcome(boolean value) { checkedForUserWelcome = value; } public boolean getCheckedForUserWelcome() { return checkedForUserWelcome; } public void setUserWelcomeEnabled(boolean value) { userWelcomeEnabled = value; SharedPreferences settings; settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_USER_WELCOME_ENABLED, userWelcomeEnabled); editor.apply(); } public boolean getUserWelcomeEnabled() { return userWelcomeEnabled; } // ********************************************************************************* // * HowTo // ********************************************************************************* public void setCheckedForTutorial(boolean value) { checkedForTutorial = value; } public boolean getCheckedForTutorial() { return checkedForTutorial; } public void setTutorialEnabled(boolean value) { tutorialEnabled = value; SharedPreferences settings; settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_TUTORIAL_ENABLED, tutorialEnabled); editor.apply(); } public boolean getTutorialEnabled() { return tutorialEnabled; } public void setSixMonthAlarmEnabled(boolean value) { sixMonthAlarmEnabled = value; SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_SIX_MONTH_ALARM_ENABLED, sixMonthAlarmEnabled); editor.apply(); } // ********************************************************************************* // * Hints // ********************************************************************************* public void setHintDontRepeatTrips(boolean value) { hintDontRepeatTrips = value; SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_HINT_DONT_REPEAT_TRIPS, hintDontRepeatTrips); editor.apply(); } public boolean getHintDontRepeatTrips() { return hintDontRepeatTrips; } public void setHintDoReportNow(boolean value) { hintDoReportNow = value; SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_HINT_DO_REPORT_NOW, hintDoReportNow); editor.apply(); } public boolean getHintDoReportNow() { return hintDoReportNow; } public void setHintDoReportLater(boolean value) { hintDoReportLater = value; SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_HINT_DO_REPORT_LATER, hintDoReportLater); editor.apply(); } public boolean getHintDoReportLater() { return hintDoReportLater; } public void setHintEmailNameAndNumber(boolean value) { hintEmailNameAndNumber = value; SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putBoolean(SETTING_HINT_EMAIL_NAME_AND_NUMBER, hintEmailNameAndNumber); editor.apply(); } public boolean getHintEmailNameAndNumber() { return hintEmailNameAndNumber; } // ********************************************************************************* // * FirstUse // ********************************************************************************* /** * Sets SETTING_FIRST_USE, and SETTING_VERSION_CODE settings * @return new value of SETTING_FIRST_USE */ private long generateFirstUse() { long value = System.currentTimeMillis(); SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putLong(SETTING_FIRST_USE, value); editor.apply(); return value; } public long getFirstUse() { return firstUse; } public String getFirstUseString() { return (new SimpleDateFormat("MMMM d, y h:mm a")).format(firstUse); } public String getUserId() { return userId; } private String generateUserId() { String value = ANDROID_USER + UUID.randomUUID().toString(); SharedPreferences settings = getSharedPreferences(PREFS_APPLICATION, MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor = settings.edit(); editor.putString(SETTING_USER_ID, value); editor.apply(); return value; } // ********************************************************************************* // * // ********************************************************************************* public void ResumeNotification() { if (isRecording()) { startRecordingNotification(lastTripStartTime); } } public void startRecordingNotification(double startTime) { // Add the notify bar and blinking light MyNotifiers.setRecordingNotification(this); } public void clearRecordingNotifications() { MyNotifiers.cancelRecordingNotification(this.getBaseContext()); } public void clearReminderNotifications() { MyNotifiers.cancelReminderNotification(this.getBaseContext()); } // ********************************************************************************* // * // ********************************************************************************* public Location getLastKnownLocation() { LocationManager lm = null; List<String> providers = null; Location location = null; if (null != (lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE))) { if (null != (providers = lm.getProviders(true))) { /* Loop over the array backwards, and if you get a location, then break out the loop*/ for (int i = providers.size() - 1; i >= 0; --i) { if (null != (location = lm.getLastKnownLocation(providers.get(i)))) { break; } } } } return location; } private void loadDeviceInfo() { // Determine application information versionName = ""; versionCode = 0; try { Context context = this.getBaseContext(); PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); versionName = pInfo.versionName; versionCode = pInfo.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } appVersion = versionName + " (" + versionCode + ") on Android " + Build.VERSION.RELEASE; // Determine model information String manufacturer = Build.MANUFACTURER; String model = Build.MODEL; if (model.startsWith(manufacturer)) { deviceModel = capitalize(model); } else { deviceModel = capitalize(manufacturer) + " " + model; } } public String getVersionName() { return versionName; } public int getVersionCode() { return versionCode; } public String getAppVersion() { return appVersion; } public String getDeviceModel() { return (deviceModel); } private String capitalize(String s) { if (s == null || s.length() == 0) { return ""; } char first = s.charAt(0); if (Character.isUpperCase(first)) { return s; } else { return Character.toUpperCase(first) + s.substring(1); } } }