ContactDeletionInteraction.java revision d7c148bc7331ee405ea2932a63cb12bde259e93c
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.contacts.interactions; 18 19import com.android.contacts.ContactSaveService; 20import com.android.contacts.R; 21import com.android.contacts.model.AccountType; 22import com.android.contacts.model.AccountTypeManager; 23import com.google.android.collect.Sets; 24 25import android.app.Activity; 26import android.app.AlertDialog; 27import android.app.Fragment; 28import android.app.FragmentManager; 29import android.app.LoaderManager.LoaderCallbacks; 30import android.content.Context; 31import android.content.CursorLoader; 32import android.content.DialogInterface; 33import android.content.DialogInterface.OnDismissListener; 34import android.content.Loader; 35import android.database.Cursor; 36import android.net.Uri; 37import android.os.Bundle; 38import android.provider.ContactsContract.Contacts; 39import android.provider.ContactsContract.Contacts.Entity; 40 41import java.util.HashSet; 42 43/** 44 * An interaction invoked to delete a contact. 45 */ 46public class ContactDeletionInteraction extends Fragment 47 implements LoaderCallbacks<Cursor>, OnDismissListener { 48 49 private static final String FRAGMENT_TAG = "deleteContact"; 50 51 private static final String KEY_ACTIVE = "active"; 52 private static final String KEY_CONTACT_URI = "contactUri"; 53 private static final String KEY_FINISH_WHEN_DONE = "finishWhenDone"; 54 public static final String ARG_CONTACT_URI = "contactUri"; 55 56 private static final String[] ENTITY_PROJECTION = new String[] { 57 Entity.RAW_CONTACT_ID, //0 58 Entity.ACCOUNT_TYPE, //1 59 Entity.CONTACT_ID, // 2 60 Entity.LOOKUP_KEY, // 3 61 }; 62 63 private static final int COLUMN_INDEX_RAW_CONTACT_ID = 0; 64 private static final int COLUMN_INDEX_ACCOUNT_TYPE = 1; 65 private static final int COLUMN_INDEX_CONTACT_ID = 2; 66 private static final int COLUMN_INDEX_LOOKUP_KEY = 3; 67 68 private boolean mActive; 69 private Uri mContactUri; 70 private boolean mFinishActivityWhenDone; 71 private Context mContext; 72 73 private AlertDialog mDialog; 74 75 // Visible for testing 76 int mMessageId; 77 78 public static ContactDeletionInteraction start( 79 Activity activity, Uri contactUri, boolean finishActivityWhenDone) { 80 if (contactUri == null) { 81 return null; 82 } 83 84 FragmentManager fragmentManager = activity.getFragmentManager(); 85 ContactDeletionInteraction fragment = 86 (ContactDeletionInteraction) fragmentManager.findFragmentByTag(FRAGMENT_TAG); 87 if (fragment == null) { 88 fragment = new ContactDeletionInteraction(); 89 fragment.setContactUri(contactUri); 90 fragment.setFinishActivityWhenDone(finishActivityWhenDone); 91 fragmentManager.beginTransaction().add(fragment, FRAGMENT_TAG).commit(); 92 } else { 93 fragment.setContactUri(contactUri); 94 fragment.setFinishActivityWhenDone(finishActivityWhenDone); 95 } 96 return fragment; 97 } 98 99 @Override 100 public void onAttach(Activity activity) { 101 super.onAttach(activity); 102 mContext = activity; 103 } 104 105 @Override 106 public void onDestroyView() { 107 super.onDestroyView(); 108 if (mDialog != null && mDialog.isShowing()) { 109 mDialog.setOnDismissListener(null); 110 mDialog.dismiss(); 111 mDialog = null; 112 } 113 } 114 115 public void setContactUri(Uri contactUri) { 116 mContactUri = contactUri; 117 mActive = true; 118 if (isStarted()) { 119 Bundle args = new Bundle(); 120 args.putParcelable(ARG_CONTACT_URI, mContactUri); 121 getLoaderManager().restartLoader(R.id.dialog_delete_contact_loader_id, args, this); 122 } 123 } 124 125 private void setFinishActivityWhenDone(boolean finishActivityWhenDone) { 126 this.mFinishActivityWhenDone = finishActivityWhenDone; 127 128 } 129 130 /* Visible for testing */ 131 boolean isStarted() { 132 return isAdded(); 133 } 134 135 @Override 136 public void onStart() { 137 if (mActive) { 138 Bundle args = new Bundle(); 139 args.putParcelable(ARG_CONTACT_URI, mContactUri); 140 getLoaderManager().initLoader(R.id.dialog_delete_contact_loader_id, args, this); 141 } 142 super.onStart(); 143 } 144 145 @Override 146 public void onStop() { 147 super.onStop(); 148 if (mDialog != null) { 149 mDialog.hide(); 150 } 151 } 152 153 @Override 154 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 155 Uri contactUri = args.getParcelable(ARG_CONTACT_URI); 156 return new CursorLoader(mContext, 157 Uri.withAppendedPath(contactUri, Entity.CONTENT_DIRECTORY), ENTITY_PROJECTION, 158 null, null, null); 159 } 160 161 @Override 162 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 163 if (mDialog != null) { 164 mDialog.dismiss(); 165 mDialog = null; 166 } 167 168 if (!mActive) { 169 return; 170 } 171 172 long contactId = 0; 173 String lookupKey = null; 174 175 // This cursor may contain duplicate raw contacts, so we need to de-dupe them first 176 HashSet<Long> readOnlyRawContacts = Sets.newHashSet(); 177 HashSet<Long> writableRawContacts = Sets.newHashSet(); 178 179 AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity()); 180 cursor.moveToPosition(-1); 181 while (cursor.moveToNext()) { 182 final long rawContactId = cursor.getLong(COLUMN_INDEX_RAW_CONTACT_ID); 183 final String accountType = cursor.getString(COLUMN_INDEX_ACCOUNT_TYPE); 184 contactId = cursor.getLong(COLUMN_INDEX_CONTACT_ID); 185 lookupKey = cursor.getString(COLUMN_INDEX_LOOKUP_KEY); 186 AccountType type = accountTypes.getAccountType(accountType); 187 boolean readonly = type != null && type.readOnly; 188 if (readonly) { 189 readOnlyRawContacts.add(rawContactId); 190 } else { 191 writableRawContacts.add(rawContactId); 192 } 193 } 194 195 int readOnlyCount = readOnlyRawContacts.size(); 196 int writableCount = writableRawContacts.size(); 197 if (readOnlyCount > 0 && writableCount > 0) { 198 mMessageId = R.string.readOnlyContactDeleteConfirmation; 199 } else if (readOnlyCount > 0 && writableCount == 0) { 200 mMessageId = R.string.readOnlyContactWarning; 201 } else if (readOnlyCount == 0 && writableCount > 1) { 202 mMessageId = R.string.multipleContactDeleteConfirmation; 203 } else { 204 mMessageId = R.string.deleteConfirmation; 205 } 206 207 final Uri contactUri = Contacts.getLookupUri(contactId, lookupKey); 208 showDialog(mMessageId, contactUri); 209 210 // We don't want onLoadFinished() calls any more, which may come when the database is 211 // updating. 212 getLoaderManager().destroyLoader(R.id.dialog_delete_contact_loader_id); 213 } 214 215 @Override 216 public void onLoaderReset(Loader<Cursor> loader) { 217 } 218 219 private void showDialog(int messageId, final Uri contactUri) { 220 mDialog = new AlertDialog.Builder(getActivity()) 221 .setTitle(R.string.deleteConfirmation_title) 222 .setIconAttribute(android.R.attr.alertDialogIcon) 223 .setMessage(messageId) 224 .setNegativeButton(android.R.string.cancel, null) 225 .setPositiveButton(android.R.string.ok, 226 new DialogInterface.OnClickListener() { 227 @Override 228 public void onClick(DialogInterface dialog, int whichButton) { 229 doDeleteContact(contactUri); 230 } 231 } 232 ) 233 .create(); 234 235 mDialog.setOnDismissListener(this); 236 mDialog.show(); 237 } 238 239 @Override 240 public void onDismiss(DialogInterface dialog) { 241 mActive = false; 242 mDialog = null; 243 } 244 245 @Override 246 public void onSaveInstanceState(Bundle outState) { 247 super.onSaveInstanceState(outState); 248 outState.putBoolean(KEY_ACTIVE, mActive); 249 outState.putParcelable(KEY_CONTACT_URI, mContactUri); 250 outState.putBoolean(KEY_FINISH_WHEN_DONE, mFinishActivityWhenDone); 251 } 252 253 @Override 254 public void onActivityCreated(Bundle savedInstanceState) { 255 super.onActivityCreated(savedInstanceState); 256 if (savedInstanceState != null) { 257 mActive = savedInstanceState.getBoolean(KEY_ACTIVE); 258 mContactUri = savedInstanceState.getParcelable(KEY_CONTACT_URI); 259 mFinishActivityWhenDone = savedInstanceState.getBoolean(KEY_FINISH_WHEN_DONE); 260 } 261 } 262 263 protected void doDeleteContact(Uri contactUri) { 264 mContext.startService(ContactSaveService.createDeleteContactIntent(mContext, contactUri)); 265 if (isAdded() && mFinishActivityWhenDone) { 266 getActivity().finish(); 267 } 268 } 269} 270