blob: 666c65d84a6267df8988c11e3d8ecbc990429f83 [file] [log] [blame]
/*
* 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();
}
}