Commit e6979d3e authored by Roger Barton's avatar Roger Barton
Browse files

Merge branch 'checkin'

parents ea75aab9 77837476
Pipeline #5894 passed with stages
in 5 minutes and 31 seconds
......@@ -43,11 +43,9 @@
<activity
android:name=".core.LoginActivity"
android:configChanges="keyboardHidden|orientation|layoutDirection|screenSize|locale"
android:label="">
android:label=""
android:parentActivityName=".core.MainActivity">
<!--android:windowSoftInputMode="stateVisible" use this to make the keyboard show when the activity is started-->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="ch.amiv.android_app.core.MainActivity" />
</activity>
<activity
......@@ -60,27 +58,20 @@
android:configChanges="layoutDirection|locale"
android:label=""
android:parentActivityName=".core.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="ch.amiv.android_app.core.MainActivity" />
</activity>
<activity
android:name=".events.EventDetailActivity"
android:configChanges="orientation|layoutDirection|locale"
android:theme="@style/AppThemeLight">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="ch.amiv.android_app.core.MainActivity" />
android:theme="@style/AppThemeLight"
android:parentActivityName=".core.MainActivity">
</activity>
<activity
android:name=".jobs.JobDetailActivity"
android:configChanges="orientation|layoutDirection|locale"
android:theme="@style/AppThemeLight">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="ch.amiv.android_app.core.MainActivity" />
android:theme="@style/AppThemeLight"
android:parentActivityName=".core.MainActivity">
</activity>
<activity
......@@ -94,32 +85,29 @@
android:name=".checkin.MainActivity"
android:label="@string/app_name_checkin"
android:screenOrientation="portrait"
android:theme="@style/AmivTheme" />
android:configChanges="keyboardHidden|orientation|layoutDirection|screenSize|locale"
android:parentActivityName=".core.MainActivity"/>
<activity
android:name=".checkin.ScanActivity"
android:label="@string/app_name_checkin"
android:screenOrientation="portrait"
android:theme="@style/AmivTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".checkin.MainActivity" />
android:theme="@style/AmivTheme"
android:parentActivityName=".checkin.MainActivity">
</activity>
<activity
android:name=".checkin.SettingsActivity"
android:label="@string/app_name_checkin"
android:screenOrientation="portrait"
android:theme="@style/AmivTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".checkin.MainActivity" />
android:parentActivityName=".checkin.MainActivity">
</activity>
<activity
android:name=".checkin.MemberListActivity"
android:label="@string/app_name_checkin"
android:theme="@style/AmivTheme">
android:theme="@style/AmivTheme"
android:parentActivityName=".checkin.ScanActivity">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
......@@ -127,18 +115,13 @@
<meta-data
android:name="android.app.searchable"
android:resource="@xml/checkin_searchable" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".checkin.ScanActivity" />
</activity>
<activity
android:name=".checkin.SearchMembersActivity"
android:label="@string/app_name_checkin"
android:theme="@style/AmivTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".checkin.MemberListActivity" />
android:theme="@style/AmivTheme"
android:parentActivityName=".checkin.MemberListActivity">
</activity>
<!-- Demo -->
......
package ch.amiv.android_app.checkin;
import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
......@@ -25,6 +22,7 @@ import java.lang.reflect.Field;
import ch.amiv.android_app.R;
import ch.amiv.android_app.core.UserInfo;
import ch.amiv.android_app.util.Util;
public class BarcodeIdActivity extends AppCompatActivity {
......@@ -39,9 +37,8 @@ public class BarcodeIdActivity extends AppCompatActivity {
setContentView(R.layout.checkin_activity_barcode_id);
//Set up toolbar and back button
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Util.SetupToolbar(this, true);
//Generate barcode after the UI has been setup
barcodeImageView = findViewById(R.id.barcodeImage);
......
......@@ -6,19 +6,18 @@ package ch.amiv.android_app.checkin;
*/
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
......@@ -27,6 +26,7 @@ import android.widget.TextView;
import ch.amiv.android_app.R;
import ch.amiv.android_app.core.Settings;
import ch.amiv.android_app.util.Util;
public class MainActivity extends AppCompatActivity {
public static String CurrentPin;
......@@ -39,6 +39,7 @@ public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Util.SetWindowResizing(this, true);
setContentView(R.layout.checkin_activity_main);
InitialiseUI();
......@@ -52,10 +53,40 @@ public class MainActivity extends AppCompatActivity {
Settings.CancelVibrate();
}
//region ---Toolbar
/**
* Inflate the menu in the toolbar; this adds items to the action bar if it is present.
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.checkin_ac_main_toolbar_menu, menu);
return super.onCreateOptionsMenu(menu);
}
/**
* Detecting when the toolbar button is pressed
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_settings) {
StartSettingsActivity();
return true;
}
return super.onOptionsItemSelected(item);
}
//endregion
private void InitialiseUI()
{
Util.SetupToolbar(this, true);
mPinField = findViewById(R.id.PinField);
mInvalidPinLabel = findViewById(R.id.InvalidPinLabel);
mInvalidPinLabel = findViewById(R.id.pinStatusLabel);
mInvalidPinLabel.setText("");
mOpenRecent = findViewById(R.id.openRecent);
mPinField.setOnKeyListener(new View.OnKeyListener() {
......@@ -71,12 +102,13 @@ public class MainActivity extends AppCompatActivity {
String lastPin = Settings.GetPref(Settings.recentEventPin, getApplicationContext());
mOpenRecent.setEnabled(!lastPin.isEmpty());
/*Think this animation causes flashing screen bug, when the activity starts
View logo = findViewById(R.id.logoImage);
if(logo != null) {
Animation animation = AnimationUtils.loadAnimation(this, R.anim.item_anim_pop);
animation.setDuration(150);
logo.startAnimation(animation);
}
}*/
}
private void CheckPermissions()
......@@ -115,6 +147,7 @@ public class MainActivity extends AppCompatActivity {
if(mWaitingOnServer || (!openRecent && mPinField.getText().toString().isEmpty())) //prevents submitting a second pin while still waiting on the response for the first pin
return;
mWaitingOnServer = true;
mInvalidPinLabel.setText(R.string.wait);
if(!ServerRequests.CheckConnection(getApplicationContext())) {
ApplyServerResponse(true, 0, getResources().getString(R.string.no_internet));
......@@ -163,19 +196,18 @@ public class MainActivity extends AppCompatActivity {
Log.e("postrequest", "Response from server for pin submission: " + statusCode + " with text: " + responseText + " on event pin: " + MainActivity.CurrentPin);
if(statusCode == 200) { //success
mInvalidPinLabel.setText(R.string.success);
Settings.SetPref(Settings.recentEventPin, CurrentPin, getApplicationContext()); //store as last used pin
mOpenRecent.setEnabled(true);
StartScanActivity();
}
else if(statusCode == 401)//invalid pin
{
mInvalidPinLabel.setVisibility(View.VISIBLE);
mInvalidPinLabel.setText(responseText);
mPinField.setText("");
}
else if (statusCode == 0) //no internet connection
{
mInvalidPinLabel.setVisibility(View.VISIBLE);
mInvalidPinLabel.setText(R.string.no_internet);
}
else //Other error
......@@ -186,7 +218,6 @@ public class MainActivity extends AppCompatActivity {
private void InvalidUrlResponse()
{
mInvalidPinLabel.setVisibility(View.VISIBLE);
mInvalidPinLabel.setText(R.string.invalid_url);
}
......@@ -195,14 +226,13 @@ public class MainActivity extends AppCompatActivity {
{
mWaitingOnServer = false;
mPinField.setText(""); //clear pin field
mInvalidPinLabel.setVisibility(View.INVISIBLE);
EventDatabase.instance = null;
Intent intent = new Intent(this, ScanActivity.class);
startActivity(intent);
}
public void StartSettingsActivity(View view)
public void StartSettingsActivity()
{
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
......@@ -213,7 +243,20 @@ public class MainActivity extends AppCompatActivity {
*/
public void GoToWebsite(View view)
{
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(SettingsActivity.GetServerURL(this)));
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(Settings.GetPref(Settings.checkin_url, getApplicationContext())));
startActivity(browserIntent);
}
@Override
protected void onStop() {
super.onStop();
Util.SetWindowResizing(this, false);
}
@Override
protected void onResume() {
super.onResume();
Util.SetWindowResizing(this, true);
mInvalidPinLabel.setText("");
}
}
......@@ -14,6 +14,7 @@ import android.view.Window;
import android.view.animation.AnimationUtils;
import ch.amiv.android_app.R;
import ch.amiv.android_app.core.Settings;
/**
* This activity is for displaying the list of signed in members, similar to what is seen in the checkin website in the other amiv checkin project.
......@@ -39,8 +40,8 @@ public class MemberListActivity extends AppCompatActivity {
actionBar.setTitle(EventDatabase.instance.eventData.name);
}
});
if(SettingsActivity.GetAutoRefresh(getApplicationContext()))
handler.postDelayed(this, SettingsActivity.GetRefreshFrequency(getApplicationContext()));
if(Settings.GetBoolPref(Settings.checkin_autoUpdate, getApplicationContext()))
handler.postDelayed(this, SettingsActivity.GetRefreshRateMillis(getApplicationContext()));
}
};
......
......@@ -17,7 +17,7 @@ import ch.amiv.android_app.R;
*/
public class MemberListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<String> headerList = new ArrayList<String>();
private final List<Integer> headerList = new ArrayList<>();
private final List<KeyValuePair> statList;
private final List<Member> memberList;
private final List<KeyValuePair> eventInfoList;
......@@ -71,9 +71,9 @@ public class MemberListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
}
public MemberListAdapter(List<Member> _members, List<KeyValuePair> _stats, List<KeyValuePair> _eventInfos) {
headerList.add("Stats");
headerList.add("People");
headerList.add("Event Info");
headerList.add(R.string.stat_title);
headerList.add(R.string.people_title);
headerList.add(R.string.event_info_title);
memberList = _members;
statList = _stats;
eventInfoList = _eventInfos;
......
......@@ -10,25 +10,28 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.vision.CameraSource;
import com.google.android.gms.vision.Detector;
......@@ -41,7 +44,6 @@ import org.json.JSONObject;
import java.io.IOException;
import ch.amiv.android_app.R;
import ch.amiv.android_app.core.Settings;
public class ScanActivity extends AppCompatActivity {
......@@ -58,8 +60,8 @@ public class ScanActivity extends AppCompatActivity {
@Override
public void run() {
RefreshMemberDB();
if(SettingsActivity.GetAutoRefresh(getApplicationContext()))
handler.postDelayed(this, SettingsActivity.GetRefreshFrequency(getApplicationContext())); //ensure to call this same runnable again so it repeats, if this is allowed
if(Settings.GetBoolPref(Settings.checkin_autoUpdate, getApplicationContext()))
handler.postDelayed(this, SettingsActivity.GetRefreshRateMillis(getApplicationContext())); //ensure to call this same runnable again so it repeats, if this is allowed
}
};
......@@ -71,6 +73,7 @@ public class ScanActivity extends AppCompatActivity {
private EditText mLegiInputField;
private TextView mWaitLabel;
private TextView mResponseLabel;
private float mResponseLabelDefFontSize;
private ImageView mTickImage;
private ImageView mCrossImage;
private TextView mCheckinCountLabel;
......@@ -124,6 +127,7 @@ public class ScanActivity extends AppCompatActivity {
mCheckInSwitchLabel_Out = findViewById(R.id.CheckOutLabel);
mWaitLabel = findViewById(R.id.PleaseWaitLabel);
mResponseLabel = findViewById(R.id.ResponseLabel);
mResponseLabelDefFontSize = mResponseLabel.getTextSize(); //Note is in pixels, *not* sp
mTickImage = findViewById(R.id.TickImage);
mCrossImage = findViewById(R.id.CrossImage);
mCheckinCountLabel = findViewById(R.id.CheckInCountLabel);
......@@ -154,6 +158,16 @@ public class ScanActivity extends AppCompatActivity {
}
}
});
//This sets the action when pressing enter whilst editing the mLegiInputField so we immediately submit but dont close the keyboard
mLegiInputField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if(actionId == EditorInfo.IME_ACTION_GO) //Note:this needs to match the imeOptions in the layout file for the password field
SubmitLegiNrFromTextField(null); //If we pressed the enter button then submit the details
return true; //return true to keep the keyboard open, in case the user has to re-enter details
}
});
}
/**
......@@ -308,7 +322,6 @@ public class ScanActivity extends AppCompatActivity {
}
};
Log.e("postrequest", "Params sent: pin=" + MainActivity.CurrentPin + ", info=" + leginr + ", checkmode=" + (mIsCheckingIn ? "in" : "out") + ", URL used: " + SettingsActivity.GetServerURL(getApplicationContext()));
ServerRequests.CheckLegi(this, callback, leginr, mIsCheckingIn);
}
......@@ -325,7 +338,7 @@ public class ScanActivity extends AppCompatActivity {
if(statusCode == 200) { //success
mResponseLabel.setVisibility(View.VISIBLE);
mResponseLabel.setText(message);
mResponseLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResponseLabelDefFontSize);
mTickImage.setVisibility(View.VISIBLE);
mBGTint.setVisibility(View.VISIBLE);
mTickImage.startAnimation(AnimationUtils.loadAnimation(this, R.anim.item_anim_grow));
......@@ -408,6 +421,12 @@ public class ScanActivity extends AppCompatActivity {
Settings.Vibrate(Settings.VibrateTime.LONG, getApplicationContext());
}
//decrease font size for long messages, usually errors
if (responseText.length() < 40)
mResponseLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResponseLabelDefFontSize);
else
mResponseLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f);
RefreshMemberDB();
}
......@@ -418,6 +437,7 @@ public class ScanActivity extends AppCompatActivity {
{
mResponseLabel.setText("");
mResponseLabel.setVisibility(View.INVISIBLE);
mResponseLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mResponseLabelDefFontSize);
mTickImage.setVisibility(View.INVISIBLE);
mCrossImage.setVisibility(View.INVISIBLE);
mCheckinCountLabel.setVisibility(View.INVISIBLE);
......@@ -519,10 +539,11 @@ public class ScanActivity extends AppCompatActivity {
@Override
public void onBackPressed() { //Used to press back twice to exit scanning screen, prevent accidental logouts
if (timeBackPressed + BACKBUTTON_REPEAT_TIME > System.currentTimeMillis())
if (timeBackPressed + BACKBUTTON_REPEAT_TIME > System.currentTimeMillis()) {
super.onBackPressed();
}
else
Toast.makeText(getBaseContext(), "Press Again To Logout", Toast.LENGTH_SHORT).show();
Snackbar.make(mCameraView, R.string.press_again_logout, BACKBUTTON_REPEAT_TIME).show();
timeBackPressed = System.currentTimeMillis();
}
......
......@@ -17,6 +17,7 @@ import java.util.ArrayList;
import java.util.List;
import ch.amiv.android_app.R;
import ch.amiv.android_app.core.Settings;
public class SearchMembersActivity extends AppCompatActivity {
......@@ -40,8 +41,8 @@ public class SearchMembersActivity extends AppCompatActivity {
actionBar.setTitle(EventDatabase.instance.eventData.name);
}
});
if(SettingsActivity.GetAutoRefresh(getApplicationContext()))
handler.postDelayed(this, SettingsActivity.GetRefreshFrequency(getApplicationContext()));
if(Settings.GetBoolPref(Settings.checkin_autoUpdate, getApplicationContext()))
handler.postDelayed(this, SettingsActivity.GetRefreshRateMillis(getApplicationContext()));
}
};
......
......@@ -6,6 +6,7 @@ import android.net.NetworkInfo;
import android.util.Log;
import com.android.volley.AuthFailureError;
import com.android.volley.BuildConfig;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
......@@ -22,6 +23,8 @@ import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import ch.amiv.android_app.core.Settings;
/**
* Created by Roger on 13-Feb-18.
*
......@@ -57,9 +60,9 @@ public final class ServerRequests {
if(!CheckConnection(context))
return;
Log.e("postrequest", "Params sent: pin=" + MainActivity.CurrentPin + ", URL used: " + SettingsActivity.GetServerURL(context) + ON_SUBMIT_PIN_URL_EXT);
Log.e("postrequest", "Params sent: pin=" + MainActivity.CurrentPin + ", URL used: " + Settings.GetPref(Settings.checkin_url, context) + ON_SUBMIT_PIN_URL_EXT);
StringRequest postRequest = new StringRequest(Request.Method.POST, SettingsActivity.GetServerURL(context) + ON_SUBMIT_PIN_URL_EXT
StringRequest postRequest = new StringRequest(Request.Method.POST, Settings.GetPref(Settings.checkin_url, context) + ON_SUBMIT_PIN_URL_EXT
, new Response.Listener<String>() { @Override public void onResponse(String response){} }
, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error){} })
{
......@@ -99,8 +102,11 @@ public final class ServerRequests {
public static void CheckLegi(final Context context, final OnJsonReceivedCallback callback, final String legi, final boolean isCheckingIn)
{
if(BuildConfig.DEBUG)
Log.e("postrequest", "Params sent: pin=" + MainActivity.CurrentPin + ", info=" + legi + ", checkmode=" + (isCheckingIn ? "in" : "out") +
", URL used: " + Settings.GetPref(Settings.checkin_url, context));
//Note: server will send a Json if the response is valid, ie the person has been checked in, else a string. This is to get the member type. Yet we still need to do a stringRequest
StringRequest req = new StringRequest(Request.Method.POST, SettingsActivity.GetServerURL(context) + ON_SUBMIT_LEGI_URL_EXT
StringRequest req = new StringRequest(Request.Method.POST, Settings.GetPref(Settings.checkin_url, context) + ON_SUBMIT_LEGI_URL_EXT
, new Response.Listener<String>() { @Override public void onResponse(String response) {}} //initialise with empty response listeners as we will handle the response in the parseNetworkResponse and parseNetworkError functions
, new Response.ErrorListener() {@Override public void onErrorResponse(VolleyError error) {}})
{
......@@ -155,9 +161,9 @@ public final class ServerRequests {
if(!CheckConnection(context))
return;
Log.e("postrequest", "Params sent: pin=" + MainActivity.CurrentPin + ", URL used: " + SettingsActivity.GetServerURL(context) + GET_DATA_URL_EXT);
Log.e("postrequest", "Params sent: pin=" + MainActivity.CurrentPin + ", URL used: " + Settings.GetPref(Settings.checkin_url, context) + GET_DATA_URL_EXT);
JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, SettingsActivity.GetServerURL(context) + GET_DATA_URL_EXT,
JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, Settings.GetPref(Settings.checkin_url, context) + GET_DATA_URL_EXT,
(JSONObject) null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
......
......@@ -7,7 +7,6 @@ package ch.amiv.android_app.checkin;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.math.MathUtils;
import android.support.v7.app.AppCompatActivity;
......@@ -16,19 +15,13 @@ import android.widget.CheckBox;
import android.widget.EditText;
import ch.amiv.android_app.R;
import ch.amiv.android_app.core.Settings;
import ch.amiv.android_app.util.Util;
/**
* This activity is for settings *specific* to the checkin microapp, we still use the core.Settings to store sharedPrefs/variables. Mainly handles UI
*/
public class SettingsActivity extends AppCompatActivity {
private static String DEF_URL = "https://checkin.amiv.ethz.ch"; //NOTE: Set default value before build, also change the 'checkin_server_url' string in strings.xml to adapt UI
//Vars for saving/reading the url from shared prefs, to allow saving between sessions. For each variable, have a key to access it and a default value
private static SharedPreferences SHARED_PREFS;
private static String SHARED_PREFS_KEY = "com.amivlegiscanner.app";
private static String URL_PREF_KEY = "com.amivlegiscanner.app.serverurl";
private static String AUTO_UPDATE_STATS_PREF_KEY = "com.amivlegiscanner.app.autorefresh";
public static boolean DEF_AUTO_UPDATE_STATS = true;
private static String REFRESH_FREQUENCY_KEY = "com.amivlegiscanner.app.refreshfrequency";
public static float DEF_REFRESH_FREQUENCY = 20f;
private EditText mUrlField;
private CheckBox mAutoRefreshCheck;
private EditText mRefreshFreqField;
......@@ -37,13 +30,19 @@ public class SettingsActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.checkin_activity_settings);