blob: 47a86053cd198257ee196f77c0c1d0dc294be9dd [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.content.Context;
import android.net.Uri;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.provider.ContactsContract;
import android.util.ArraySet;
import android.util.AttributeSet;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import java.util.Collections;
import java.util.Set;
/**
* Custom {@link PreferenceCategory} that deals with contacts being deleted from the contacts app.
*
* <p>Contacts are stored internally using their CONTENT_LOOKUP_URI.
*/
public class EmergencyContactsPreference extends PreferenceCategory
implements ReloadablePreferenceInterface,
ContactPreference.RemoveContactPreferenceListener {
private boolean mReadOnly = false;
/** Stores the emergency contacts CONTENT_LOOKUP_URI */
private Set<Uri> mEmergencyContacts = new ArraySet<Uri>();
public EmergencyContactsPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/** Sets whether this category will be used in read only mode or in edit mode. */
public void setReadOnly(boolean readOnly) {
mReadOnly = readOnly;
}
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
setEmergencyContacts(restorePersistedValue ?
getPersistedEmergencyContacts() :
deserializeAndFilterExisting((Set<String>) defaultValue));
}
@Override
public void reloadFromPreference() {
setEmergencyContacts(getPersistedEmergencyContacts());
}
@Override
public void onRemoveContactPreference(ContactPreference contactPreference) {
Uri newContact = contactPreference.getContactUri();
if (mEmergencyContacts.contains(newContact)) {
Set<Uri> updatedContacts = new ArraySet<Uri>((ArraySet<Uri>) mEmergencyContacts);
if (updatedContacts.remove(newContact) && callChangeListener(updatedContacts)) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETE_EMERGENCY_CONTACT);
setEmergencyContacts(updatedContacts);
}
}
}
/**
* Adds a new emergency contact. The {@code contactUri} is the CONTENT_URI corresponding to the
* contact.
*/
public void addNewEmergencyContact(Uri contactUri) {
final Uri contactLookupUri =
ContactsContract.Contacts.getLookupUri(getContext().getContentResolver(),
contactUri);
if (EmergencyContactManager.getPhoneNumbers(getContext(), contactLookupUri) == null) {
// TODO: show warning dialog: no phone number: then keep/discard
} else {
if (!mEmergencyContacts.contains(contactLookupUri)) {
Set<Uri> updatedContacts = new ArraySet<Uri>((ArraySet<Uri>) mEmergencyContacts);
if (updatedContacts.add(contactLookupUri) && callChangeListener(updatedContacts)) {
MetricsLogger.action(getContext(), MetricsEvent.ACTION_ADD_EMERGENCY_CONTACT);
setEmergencyContacts(updatedContacts);
}
}
}
}
private void setEmergencyContacts(Set<Uri> emergencyContacts) {
mEmergencyContacts = emergencyContacts;
persistEmergencyContacts(emergencyContacts);
notifyChanged();
removeAll();
for (Uri contactLookupUri : emergencyContacts) {
addContactPreference(contactLookupUri);
}
}
private void addContactPreference(Uri contactLookupUri) {
final ContactPreference contactPreference =
new ContactPreference(getContext(),
contactLookupUri,
EmergencyContactManager.getName(getContext(), contactLookupUri));
contactPreference
.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
if (mReadOnly) {
contactPreference.showCallContactDialog();
} else {
contactPreference.displayContact();
}
return true;
}
}
);
contactPreference.setRemoveContactPreferenceListener(mReadOnly ? null : this);
addPreference(contactPreference);
}
private Set<Uri> getPersistedEmergencyContacts() {
return deserializeAndFilterExisting(
getPersistedStringSet(Collections.<String>emptySet()));
}
/**
* Converts the strings to Uris and only keeps those corresponding to still existing contacts.
*/
private Set<Uri> deserializeAndFilterExisting(Set<String> emergencyContactStrings) {
Set<Uri> emergencyContacts = new ArraySet<Uri>(emergencyContactStrings.size());
for (String emergencyContact : emergencyContactStrings) {
Uri contactLookupUri = Uri.parse(emergencyContact);
if (EmergencyContactManager.isValidEmergencyContact(getContext(), contactLookupUri)) {
emergencyContacts.add(contactLookupUri);
}
}
// If not all contacts were added, then we need to overwrite the emergency contacts stored
// in shared preferences. This deals with emergency contacts being deleted from contacts:
// currently we have no way to being notified when this happens.
if (emergencyContacts.size() != emergencyContactStrings.size()) {
persistEmergencyContacts(emergencyContacts);
}
return emergencyContacts;
}
private void persistEmergencyContacts(Set<Uri> emergencyContacts) {
Set<String> emergencyContactStrings = serialize(emergencyContacts);
persistStringSet(emergencyContactStrings);
}
/** Converts the Uris to their string representation. */
private Set<String> serialize(Set<Uri> emergencyContacts) {
Set<String> emergencyContactStrings = new ArraySet<String>(emergencyContacts.size());
for (Uri contactLookupUri : emergencyContacts) {
emergencyContactStrings.add(contactLookupUri.toString());
}
return emergencyContactStrings;
}
}