EmergencyInfo V1 App code

Bug: 23591361
Change-Id: I4a973ad0a50cc4a39c2e4c84bd7a8f772cc3f359
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..2125da4
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifeq ($(TARGET_BUILD_APPS),)
+support_library_root_dir := frameworks/support
+else
+support_library_root_dir := prebuilts/sdk/current/support
+endif
+
+LOCAL_MODULE_TAGS := eng
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v14-preference \
+                               android-support-v13 \
+                               android-support-v7-appcompat \
+			       android-support-v7-preference \
+			       android-support-v7-recyclerview \
+			       android-support-v4 \
+			       android-support-design
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res \
+		      $(support_library_root_dir)/v7/appcompat/res \
+		      $(support_library_root_dir)/v7/preference/res \
+		      $(support_library_root_dir)/v7/recyclerview/res \
+		      $(support_library_root_dir)/v14/preference/res \
+                      $(support_library_root_dir)/design/res
+
+LOCAL_AAPT_FLAGS := --auto-add-overlay \
+                    --extra-packages android.support.v7.preference \
+		    --extra-packages android.support.v14.preference \
+		    --extra-packages android.support.v7.appcompat \
+		    --extra-packages android.support.v7.recyclerview \
+		    --extra-packages android.support.design
+
+LOCAL_SDK_VERSION := current
+LOCAL_PACKAGE_NAME := EmergencyInfo
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..0bbacad
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.emergency">
+
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+    <application
+        android:label="@string/app_name"
+        android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+        <activity
+            android:name=".ViewInfoActivity"
+            android:showOnLockScreen="true">
+            <intent-filter>
+                <action android:name="android.telephony.action.EMERGENCY_ASSISTANCE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".EditInfoActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/res/drawable/ic_info_black_24dp.xml b/res/drawable/ic_info_black_24dp.xml
new file mode 100644
index 0000000..34b8202
--- /dev/null
+++ b/res/drawable/ic_info_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z" />
+</vector>
diff --git a/res/drawable/ic_notifications_black_24dp.xml b/res/drawable/ic_notifications_black_24dp.xml
new file mode 100644
index 0000000..e3400cf
--- /dev/null
+++ b/res/drawable/ic_notifications_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11.5,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zm6.5,-6v-5.5c0,-3.07 -2.13,-5.64 -5,-6.32V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5v0.68c-2.87,0.68 -5,3.25 -5,6.32V16l-2,2v1h17v-1l-2,-2z" />
+</vector>
diff --git a/res/drawable/ic_sync_black_24dp.xml b/res/drawable/ic_sync_black_24dp.xml
new file mode 100644
index 0000000..3f0ac1c
--- /dev/null
+++ b/res/drawable/ic_sync_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24.0dp"
+    android:height="24.0dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01,-.25 1.97,-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0,-4.42,-3.58,-8,-8,-8zm0 14c-3.31 0,-6,-2.69,-6,-6 0,-1.01.25,-1.97.7,-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4,-4,-4,-4v3z" />
+</vector>
\ No newline at end of file
diff --git a/res/mipmap-hdpi/ic_launcher.png b/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher.png b/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher.png b/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_launcher.png b/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-xxxhdpi/ic_launcher.png b/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/res/values-v21/styles.xml b/res/values-v21/styles.xml
new file mode 100644
index 0000000..dbbdd40
--- /dev/null
+++ b/res/values-v21/styles.xml
@@ -0,0 +1,9 @@
+<resources>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+    </style>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
new file mode 100644
index 0000000..812cb7b
--- /dev/null
+++ b/res/values/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..9e16bf8
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,33 @@
+<resources>
+    <string name="app_name">Emergency Information</string>
+
+    <string name="medical_category">Health</string>
+    <string name="blood_type">Blood Type</string>
+    <string-array name="blood_type_values">
+        <item>O+</item>
+        <item>O-</item>
+        <item>A+</item>
+        <item>A-</item>
+        <item>B+</item>
+        <item>B-</item>
+        <item>AB+</item>
+        <item>AB-</item>
+    </string-array>
+
+    <string name="allergies">Allergies</string>
+    <string name="default_summary">None specified</string>
+
+    <string name="medications">Medications</string>
+    <string name="medical_conditions">Medical conditions and notes</string>
+
+    <string name="readonly_title">Lockscreen view</string>
+
+    <string name="add_emergency_contact">Add contact</string>
+    <string-array name="contact_action_choices">
+        <item>Delete emergency contact</item>
+        <item>View details</item>
+    </string-array>
+
+    <string name="unknown_contact">Unknown Contact</string>
+
+</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100644
index 0000000..b2fb37b
--- /dev/null
+++ b/res/values/styles.xml
@@ -0,0 +1,15 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+    </style>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+    </style>
+
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/res/xml/emergency_info.xml b/res/xml/emergency_info.xml
new file mode 100644
index 0000000..7d94466
--- /dev/null
+++ b/res/xml/emergency_info.xml
@@ -0,0 +1,59 @@
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
+         dismiss it. -->
+    <!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
+    <ListPreference
+        android:defaultValue="-1"
+        android:entries="@array/blood_type_values"
+        android:entryValues="@array/blood_type_values"
+        android:key="blood_type"
+        android:negativeButtonText="@null"
+        android:positiveButtonText="@null"
+        android:summary="@string/default_summary"
+        android:title="@string/blood_type" />
+
+    <!-- NOTE: EditTextPreference accepts EditText attributes. -->
+    <!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
+    <EditTextPreference
+        android:capitalize="sentences"
+        android:inputType="textCapWords"
+        android:key="allergies"
+        android:maxLines="1"
+        android:selectAllOnFocus="true"
+        android:singleLine="true"
+        android:summary="@string/default_summary"
+        android:title="@string/allergies" />
+
+    <EditTextPreference
+        android:capitalize="sentences"
+        android:inputType="textCapWords"
+        android:key="medications"
+        android:maxLines="1"
+        android:selectAllOnFocus="true"
+        android:singleLine="true"
+        android:summary="@string/default_summary"
+        android:title="@string/medications" />
+
+    <EditTextPreference
+        android:capitalize="sentences"
+        android:inputType="textCapWords"
+        android:key="medical_conditions"
+        android:maxLines="1"
+        android:selectAllOnFocus="true"
+        android:singleLine="false"
+        android:title="@string/medical_conditions" />
+    <PreferenceCategory android:key="emergency_contacts" android:title="Emergency contacts">
+    </PreferenceCategory>
+
+    <PreferenceCategory android:key="debug" android:title="Debug">
+        <Preference
+            android:title="@string/readonly_title"
+            android:key="readonly"
+            >
+            <intent android:action="android.telephony.action.EMERGENCY_ASSISTANCE" />
+        </Preference>
+    </PreferenceCategory>
+
+
+</PreferenceScreen>
diff --git a/src/com/android/emergency/AppCompatPreferenceActivity.java b/src/com/android/emergency/AppCompatPreferenceActivity.java
new file mode 100644
index 0000000..92c7843
--- /dev/null
+++ b/src/com/android/emergency/AppCompatPreferenceActivity.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.emergency;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatDelegate;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A {@link PreferenceActivity} which implements and proxies the necessary calls
+ * to be used with AppCompat.
+ */
+public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
+
+    private AppCompatDelegate mDelegate;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        getDelegate().installViewFactory();
+        getDelegate().onCreate(savedInstanceState);
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        getDelegate().onPostCreate(savedInstanceState);
+    }
+
+    public ActionBar getSupportActionBar() {
+        return getDelegate().getSupportActionBar();
+    }
+
+    public void setSupportActionBar(@Nullable Toolbar toolbar) {
+        getDelegate().setSupportActionBar(toolbar);
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        return getDelegate().getMenuInflater();
+    }
+
+    @Override
+    public void setContentView(@LayoutRes int layoutResID) {
+        getDelegate().setContentView(layoutResID);
+    }
+
+    @Override
+    public void setContentView(View view) {
+        getDelegate().setContentView(view);
+    }
+
+    @Override
+    public void setContentView(View view, ViewGroup.LayoutParams params) {
+        getDelegate().setContentView(view, params);
+    }
+
+    @Override
+    public void addContentView(View view, ViewGroup.LayoutParams params) {
+        getDelegate().addContentView(view, params);
+    }
+
+    @Override
+    protected void onPostResume() {
+        super.onPostResume();
+        getDelegate().onPostResume();
+    }
+
+    @Override
+    protected void onTitleChanged(CharSequence title, int color) {
+        super.onTitleChanged(title, color);
+        getDelegate().setTitle(title);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        getDelegate().onConfigurationChanged(newConfig);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        getDelegate().onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        getDelegate().onDestroy();
+    }
+
+    /**
+     * Sets up the {@link ActionBar}, if the API is available.
+     */
+    protected void setupActionBar() {
+        ActionBar actionBar = getSupportActionBar();
+        if (actionBar != null) {
+            // Show the Up button in the action bar.
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            // Respond to the action bar's Up/Home button.
+            case android.R.id.home:
+                onBackPressed();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void invalidateOptionsMenu() {
+        getDelegate().invalidateOptionsMenu();
+    }
+
+    private AppCompatDelegate getDelegate() {
+        if (mDelegate == null) {
+            mDelegate = AppCompatDelegate.create(this, null);
+        }
+        return mDelegate;
+    }
+}
diff --git a/src/com/android/emergency/ContactActionsDialogFragment.java b/src/com/android/emergency/ContactActionsDialogFragment.java
new file mode 100644
index 0000000..673d83f
--- /dev/null
+++ b/src/com/android/emergency/ContactActionsDialogFragment.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.emergency;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+/**
+ * A {@link DialogFragment} that displays a list of actions for an emergency contact. Call
+ * {@link #setTitle(CharSequence)} and {@link #setDialogActionCallback(DialogActionCallback)}
+ * before showing.
+ */
+public class ContactActionsDialogFragment extends DialogFragment {
+    private CharSequence mTitle = null;
+    private DialogActionCallback mDialogActionCallback = null;
+
+    /**
+     * Sets the title of the dialog.
+     */
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+    }
+
+    /**
+     * Sets the callbacks to be triggered when dialog options are selected.
+     */
+    public void setDialogActionCallback(DialogActionCallback dialogActionCallback) {
+        mDialogActionCallback = dialogActionCallback;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        if (mTitle == null) {
+            throw new IllegalArgumentException(
+                    "setTitle must be called before showing dialog");
+        }
+        if (mDialogActionCallback == null) {
+            throw new IllegalArgumentException(
+                    "setDialogActionCallback must be called before showing dialog");
+        }
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        String[] choices =
+                getContext().getResources().getStringArray(R.array.contact_action_choices);
+
+        builder.setTitle(mTitle).setItems(choices, new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dialog, int which) {
+                if (which == 0) {
+                    mDialogActionCallback.onContactDelete();
+                } else if (which == 1) {
+                    mDialogActionCallback.onContactDisplay();
+                }
+            }
+        });
+        return builder.create();
+    }
+
+    /**
+     * Callbacks for actions on a contact. Triggered when options in the dialog are selected.
+     */
+    public interface DialogActionCallback {
+        /**
+         * Callback to delete a contact.
+         */
+        void onContactDelete();
+
+        /**
+         * Callback to display a contact.
+         */
+        void onContactDisplay();
+    }
+}
diff --git a/src/com/android/emergency/ContactPreference.java b/src/com/android/emergency/ContactPreference.java
new file mode 100644
index 0000000..3ea8d39
--- /dev/null
+++ b/src/com/android/emergency/ContactPreference.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.emergency;
+
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.preference.Preference;
+import android.provider.ContactsContract;
+
+/**
+ * A {@link Preference} to display a contact using the specified URI string.
+ */
+public class ContactPreference extends Preference {
+
+    private final Uri mUri;
+
+    /**
+     * Instantiates a ContactPreference that displays an emergency contact, taking in a Context and
+     * the Uri of the contact as a String.
+     */
+    public ContactPreference(Context context, String uriString) {
+        super(context);
+        mUri = Uri.parse(uriString);
+        String name = getName();
+        setTitle((name != null) ? name : getContext().getString(R.string.unknown_contact));
+    }
+
+    /**
+     * Displays a contact card for the contact.
+     */
+    public void displayContact() {
+        Intent contactIntent = new Intent(Intent.ACTION_VIEW);
+        contactIntent.setData(getUri());
+        getContext().startActivity(contactIntent);
+    }
+
+    /**
+     * Returns the URI for the contact.
+     */
+    public Uri getUri() {
+        return mUri;
+    }
+
+    private String getName() {
+        Cursor cursor = getContext().getContentResolver().query(getUri(), null, null, null, null);
+        try {
+            if (cursor.moveToFirst()) {
+                return cursor.getString(cursor.getColumnIndex(
+                        ContactsContract.Contacts.DISPLAY_NAME));
+            }
+        } finally {
+            cursor.close();
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/emergency/EditInfoActivity.java b/src/com/android/emergency/EditInfoActivity.java
new file mode 100644
index 0000000..1da4089
--- /dev/null
+++ b/src/com/android/emergency/EditInfoActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.emergency;
+
+import android.os.Bundle;
+
+/**
+ * Activity for editing emergency information.
+ */
+public class EditInfoActivity extends AppCompatPreferenceActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setupActionBar();
+
+        // Create the fragment with readOnly set to false
+        EmergencyInfoFragment emergencyInfoFragment = EmergencyInfoFragment
+                .createEmergencyInfoFragment(false);
+
+        // Display the fragment as the main content.
+        getFragmentManager().beginTransaction().replace(android.R.id.content,
+                emergencyInfoFragment).commit();
+    }
+}
diff --git a/src/com/android/emergency/EmergencyInfoFragment.java b/src/com/android/emergency/EmergencyInfoFragment.java
new file mode 100644
index 0000000..666c65d
--- /dev/null
+++ b/src/com/android/emergency/EmergencyInfoFragment.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.emergency;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import android.preference.PreferenceScreen;
+import android.provider.ContactsContract;
+import android.support.v4.content.ContextCompat;
+import android.Manifest;
+import android.util.ArraySet;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Fragment that displays health information and emergency contacts.
+ * Takes in boolean readOnly to determine whether or not to allow information to be edited.
+ */
+public class EmergencyInfoFragment extends PreferenceFragment {
+
+    /** Result code for contact picker */
+    private static final int CONTACT_PICKER_RESULT = 1001;
+
+    /** Request code for runtime contacts permission */
+    private static final int CONTACT_PERMISSION_REQUEST = 1002;
+
+    /** Key for contact actions dialog */
+    private static final String CONTACT_ACTIONS_DIALOG_KEY = "contact_actions";
+
+    /** Key for debug preference */
+    private static final String DEBUG_KEY = "debug";
+
+    /** Key for emergency contacts preference */
+    private static final String EMERGENCY_CONTACTS_KEY = "emergency_contacts";
+
+    /** Key to look up whether or not the fragment should be read only from the bundle */
+    private static final String READ_ONLY_KEY = "read_only";
+
+    /** Keys for all editable preferences- used to set up bindings */
+    private static final String[] PREFERENCE_KEYS = {"blood_type", "allergies", "medications",
+            "medical_conditions"};
+
+    /** Whether or not this fragment should be read only */
+    private boolean mReadOnly;
+
+    /** SharedPreferences- initialized in onCreate */
+    private SharedPreferences mSharedPreferences = null;
+
+    /** Reference to the preferenceScreen controlled by this fragment */
+    private PreferenceScreen mPreferenceScreen;
+
+    /**
+     * Creates a new EmergencyInfoFragment that can be used to edit user info if {@code readOnly}
+     * is false. Otherwise, it provides a non-editable view of the emergency info.
+     */
+    public static EmergencyInfoFragment createEmergencyInfoFragment(boolean readOnly) {
+        Bundle emergencyInfoArgs = new Bundle();
+        emergencyInfoArgs.putBoolean(READ_ONLY_KEY, readOnly);
+        EmergencyInfoFragment emergencyInfoFragment = new EmergencyInfoFragment();
+        emergencyInfoFragment.setArguments(emergencyInfoArgs);
+        return emergencyInfoFragment;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        addPreferencesFromResource(R.xml.emergency_info);
+
+        mReadOnly = getArguments().getBoolean(READ_ONLY_KEY);
+        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
+        mPreferenceScreen = getPreferenceScreen();
+
+        for (String preferenceKey : PREFERENCE_KEYS) {
+            Preference preference = findPreference(preferenceKey);
+            bindPreferenceSummaryToValue(preference);
+            if (mReadOnly) {
+                preference.setEnabled(false);
+                preference.setShouldDisableView(false);
+            }
+        }
+        populateEmergencyContacts();
+        if (mReadOnly) {
+            // TODO: For supporting testing only. Remove this for launch.
+            PreferenceCategory debugPreferenceCategory =
+                    (PreferenceCategory) findPreference(DEBUG_KEY);
+            mPreferenceScreen.removePreference(debugPreferenceCategory);
+        }
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == CONTACT_PICKER_RESULT && resultCode == Activity.RESULT_OK) {
+            Uri result = data.getData();
+            // Manipulate a copy of emergency contacts rather than editing directly- see
+            // getEmergencyContacts for why this is necessary.
+            Set<String> oldContacts = getEmergencyContacts();
+            ArraySet<String> newContacts = new ArraySet<String>(oldContacts.size() + 1);
+            newContacts.addAll(oldContacts);
+
+            newContacts.add(result.toString());
+            setEmergencyContacts(newContacts);
+
+            populateEmergencyContacts();
+        }
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String permissions[],
+                                           int[] grantResults) {
+        if (requestCode == CONTACT_PERMISSION_REQUEST) {
+            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                populateEmergencyContacts();
+            } else {
+                mPreferenceScreen.removePreference(findPreference(EMERGENCY_CONTACTS_KEY));
+            }
+        }
+    }
+
+    private static final Preference.OnPreferenceChangeListener
+            sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
+        @Override
+        public boolean onPreferenceChange(Preference preference, Object value) {
+            String stringValue = value.toString();
+
+            if (preference instanceof ListPreference) {
+                ListPreference listPreference = (ListPreference) preference;
+                int index = listPreference.findIndexOfValue(stringValue);
+                preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null);
+            } else {
+                preference.setSummary(stringValue);
+            }
+            return true;
+        }
+    };
+
+    /**
+     * Binds a preference's summary to its value. More specifically, when the
+     * preference's value is changed, its summary (line of text below the
+     * preference title) is updated to reflect the value. The summary is also
+     * immediately updated upon calling this method. The exact display format is
+     * dependent on the type of preference.
+     *
+     * @see #sBindPreferenceSummaryToValueListener
+     */
+    private void bindPreferenceSummaryToValue(Preference preference) {
+        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
+
+        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
+                mSharedPreferences.getString(preference.getKey(), ""));
+    }
+
+    private void populateEmergencyContacts() {
+        PreferenceCategory emergencyContactsCategory =
+                (PreferenceCategory) findPreference(EMERGENCY_CONTACTS_KEY);
+        emergencyContactsCategory.removeAll();
+        Set<String> emergencyContacts = getEmergencyContacts();
+
+        if (!emergencyContacts.isEmpty()) {
+            // Get permission if necessary, else populate emergency contacts list
+            if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_CONTACTS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
+                        CONTACT_PERMISSION_REQUEST);
+            } else {
+                for (String contactUri : emergencyContacts) {
+                    final ContactPreference contactPreference =
+                            new ContactPreference(getContext(), contactUri);
+                    contactPreference.setOnPreferenceClickListener(
+                            createContactPreferenceClickListener(contactPreference));
+                    emergencyContactsCategory.addPreference(contactPreference);
+                }
+            }
+        }
+
+        if (!mReadOnly) {
+            // If in edit mode, add a button to create a new emergency contact.
+            emergencyContactsCategory.addPreference(createAddEmergencyContactPreference());
+        } else if (emergencyContacts.isEmpty()) {
+            // If in view mode and there are no contacts, remove the section entirely.
+            mPreferenceScreen.removePreference(emergencyContactsCategory);
+        }
+    }
+
+    private Preference.OnPreferenceClickListener createContactPreferenceClickListener(
+            final ContactPreference contactPreference) {
+        return new Preference.OnPreferenceClickListener() {
+            @Override
+            public boolean onPreferenceClick(Preference preference) {
+                final Uri contactUri = contactPreference.getUri();
+
+                if (mReadOnly) {
+                    // TODO: Call the contact instead of displaying a card.
+                    contactPreference.displayContact();
+                } else {
+                    ContactActionsDialogFragment contactActionsDialogFragment =
+                            new ContactActionsDialogFragment();
+                    contactActionsDialogFragment.setTitle(contactPreference.getTitle());
+                    contactActionsDialogFragment.setDialogActionCallback(
+                            new ContactActionsDialogFragment.DialogActionCallback() {
+                                @Override
+                                public void onContactDelete() {
+                                    // Manipulate a copy of emergency contacts rather than
+                                    // editing directly- see getEmergencyContacts for why
+                                    // this is necessary.
+                                    Set<String> oldContacts = getEmergencyContacts();
+                                    ArraySet<String> newContacts = new ArraySet<String>(
+                                            oldContacts.size());
+
+                                    newContacts.addAll(oldContacts);
+                                    newContacts.remove(contactUri.toString());
+                                    setEmergencyContacts(newContacts);
+
+                                    populateEmergencyContacts();
+                                }
+
+                                @Override
+                                public void onContactDisplay() {
+                                    contactPreference.displayContact();
+                                }
+                            });
+                    contactActionsDialogFragment.show(getFragmentManager(),
+                            CONTACT_ACTIONS_DIALOG_KEY);
+                }
+                return true;
+            }
+        };
+    }
+
+    /** Generates an add contact button */
+    private Preference createAddEmergencyContactPreference() {
+        Preference addEmergencyContact = new Preference(getContext());
+        addEmergencyContact.setTitle(getString(R.string.add_emergency_contact));
+        addEmergencyContact.setOnPreferenceClickListener(new Preference
+                .OnPreferenceClickListener() {
+            @Override
+            public boolean onPreferenceClick(Preference preference) {
+                Intent contactPickerIntent = new Intent(Intent.ACTION_PICK,
+                        ContactsContract.Contacts.CONTENT_URI);
+                startActivityForResult(contactPickerIntent, CONTACT_PICKER_RESULT);
+                return true;
+            }
+        });
+        return addEmergencyContact;
+    }
+
+
+    /**
+     * Returns a Set of stored emergency contacts. If editing, make a copy of the set as
+     * described by {@link SharedPreferences#getStringSet(String, Set<String>)}, then call
+     * {@link #setEmergencyContacts(Set)} to store the new contact information.
+     */
+    private Set<String> getEmergencyContacts() {
+        Set<String> emergencyContacts = mSharedPreferences
+                .getStringSet(EMERGENCY_CONTACTS_KEY, Collections.<String>emptySet());
+        return emergencyContacts;
+    }
+
+    private void setEmergencyContacts(Set<String> emergencyContacts) {
+        mSharedPreferences.edit().putStringSet(EMERGENCY_CONTACTS_KEY, emergencyContacts)
+                .commit();
+    }
+}
diff --git a/src/com/android/emergency/ViewInfoActivity.java b/src/com/android/emergency/ViewInfoActivity.java
new file mode 100644
index 0000000..8a3db43
--- /dev/null
+++ b/src/com/android/emergency/ViewInfoActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 com.android.emergency;
+
+import android.os.Bundle;
+import android.view.WindowManager;
+
+/**
+ * Activity for viewing emergency information.
+ */
+public class ViewInfoActivity extends AppCompatPreferenceActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+
+        super.onCreate(savedInstanceState);
+        setupActionBar();
+
+        // Create the fragment with readOnly set to true
+        EmergencyInfoFragment emergencyInfoFragment = EmergencyInfoFragment
+                .createEmergencyInfoFragment(true);
+
+        // Display the fragment as the main content.
+        getFragmentManager().beginTransaction().replace(android.R.id.content,
+                emergencyInfoFragment).commit();
+    }
+}
\ No newline at end of file