blob: 5ad05dc05aac80825ff2bba3fcdc4df393fe9645 [file] [log] [blame]
Gary Maia6c80b32016-09-30 16:34:55 -07001package com.android.contacts.activities;
2
Gary Maib9065dd2016-11-08 10:49:00 -08003import android.app.Activity;
Gary Maia6c80b32016-09-30 16:34:55 -07004import android.app.FragmentManager;
5import android.app.FragmentTransaction;
6import android.app.LoaderManager;
7import android.content.ContentUris;
8import android.content.Intent;
9import android.content.Loader;
Gary Maia6c80b32016-09-30 16:34:55 -070010import android.net.Uri;
11import android.os.Bundle;
12import android.provider.ContactsContract;
13import android.provider.ContactsContract.RawContacts;
14import android.widget.Toast;
15
16import com.android.contacts.AppCompatContactsActivity;
Gary Maib9065dd2016-11-08 10:49:00 -080017import com.android.contacts.ContactSaveService;
Gary Maia6c80b32016-09-30 16:34:55 -070018import com.android.contacts.R;
Gary Maia6c80b32016-09-30 16:34:55 -070019import com.android.contacts.editor.ContactEditorFragment;
20import com.android.contacts.editor.EditorIntents;
21import com.android.contacts.editor.PickRawContactDialogFragment;
22import com.android.contacts.editor.PickRawContactLoader;
Gary Maia1721802016-11-01 17:55:31 -070023import com.android.contacts.editor.PickRawContactLoader.RawContactsMetadata;
Gary Maib9065dd2016-11-08 10:49:00 -080024import com.android.contacts.editor.SplitContactConfirmationDialogFragment;
Gary Mai0a49afa2016-12-05 15:53:58 -080025import com.android.contacts.logging.EditorEvent;
26import com.android.contacts.logging.Logger;
27import com.android.contacts.model.AccountTypeManager;
Gary Maib9065dd2016-11-08 10:49:00 -080028import com.android.contacts.quickcontact.QuickContactActivity;
Gary Mai0a49afa2016-12-05 15:53:58 -080029import com.android.contacts.util.ImplicitIntentsUtil;
30import com.android.contacts.util.MaterialColorMapUtils.MaterialPalette;
Gary Maia1721802016-11-01 17:55:31 -070031import com.android.contactsbind.FeedbackHelper;
Gary Maia6c80b32016-09-30 16:34:55 -070032
33/**
34 * Transparent springboard activity that hosts a dialog to select a raw contact to edit.
Gary Maib9065dd2016-11-08 10:49:00 -080035 * All intents coming out from this activity have {@code FLAG_ACTIVITY_FORWARD_RESULT} set.
Gary Maia6c80b32016-09-30 16:34:55 -070036 */
Gary Mai5336e6e2016-10-23 14:17:03 -070037public class ContactEditorSpringBoardActivity extends AppCompatContactsActivity implements
Gary Maib9065dd2016-11-08 10:49:00 -080038 PickRawContactDialogFragment.PickRawContactListener,
39 SplitContactConfirmationDialogFragment.Listener {
40
Gary Maia6c80b32016-09-30 16:34:55 -070041 private static final String TAG = "EditorSpringBoard";
42 private static final String TAG_RAW_CONTACTS_DIALOG = "rawContactsDialog";
Gary Maia84f1d42016-11-29 11:16:27 -080043 private static final String KEY_RAW_CONTACTS_METADATA = "rawContactsMetadata";
Gary Maia6c80b32016-09-30 16:34:55 -070044 private static final int LOADER_RAW_CONTACTS = 1;
45
Gary Maia1721802016-11-01 17:55:31 -070046 public static final String EXTRA_SHOW_READ_ONLY = "showReadOnly";
47
Gary Maia6c80b32016-09-30 16:34:55 -070048 private Uri mUri;
Gary Maia1721802016-11-01 17:55:31 -070049 private RawContactsMetadata mResult;
Gary Maia6c80b32016-09-30 16:34:55 -070050 private MaterialPalette mMaterialPalette;
Gary Mai5a00de32016-10-19 18:20:41 -070051 private boolean mHasWritableAccount;
Gary Maib9065dd2016-11-08 10:49:00 -080052 private boolean mShowReadOnly;
Gary Mai5a00de32016-10-19 18:20:41 -070053 private int mWritableAccountPosition;
Gary Maia6c80b32016-09-30 16:34:55 -070054
55 /**
56 * The contact data loader listener.
57 */
Gary Maia1721802016-11-01 17:55:31 -070058 protected final LoaderManager.LoaderCallbacks<RawContactsMetadata> mRawContactLoaderListener =
59 new LoaderManager.LoaderCallbacks<RawContactsMetadata>() {
Gary Maia6c80b32016-09-30 16:34:55 -070060
61 @Override
Gary Maia1721802016-11-01 17:55:31 -070062 public Loader<RawContactsMetadata> onCreateLoader(int id, Bundle args) {
Gary Maia6c80b32016-09-30 16:34:55 -070063 return new PickRawContactLoader(ContactEditorSpringBoardActivity.this, mUri);
64 }
65
66 @Override
Gary Maia1721802016-11-01 17:55:31 -070067 public void onLoadFinished(Loader<RawContactsMetadata> loader,
68 RawContactsMetadata result) {
69 if (result == null) {
70 toastErrorAndFinish();
Gary Maia6c80b32016-09-30 16:34:55 -070071 return;
72 }
Gary Maia1721802016-11-01 17:55:31 -070073 mResult = result;
Gary Maib9065dd2016-11-08 10:49:00 -080074 onLoad();
Gary Maia6c80b32016-09-30 16:34:55 -070075 }
76
77 @Override
Gary Maia1721802016-11-01 17:55:31 -070078 public void onLoaderReset(Loader<RawContactsMetadata> loader) {
Gary Maia6c80b32016-09-30 16:34:55 -070079 }
80 };
81
82
83 @Override
84 protected void onCreate(Bundle savedInstanceState) {
85 super.onCreate(savedInstanceState);
86
87 if (RequestPermissionsActivity.startPermissionActivity(this)) {
88 return;
89 }
90
91 final Intent intent = getIntent();
92 final String action = intent.getAction();
93
94 if (!Intent.ACTION_EDIT.equals(action)) {
95 finish();
96 return;
97 }
98 // Just for shorter variable names.
99 final String primary = ContactEditorFragment.INTENT_EXTRA_MATERIAL_PALETTE_PRIMARY_COLOR;
100 final String secondary =
101 ContactEditorFragment.INTENT_EXTRA_MATERIAL_PALETTE_SECONDARY_COLOR;
102 if (intent.hasExtra(primary) && intent.hasExtra(secondary)) {
103 mMaterialPalette = new MaterialPalette(intent.getIntExtra(primary, -1),
104 intent.getIntExtra(secondary, -1));
105 }
Gary Maib9065dd2016-11-08 10:49:00 -0800106 mShowReadOnly = intent.getBooleanExtra(EXTRA_SHOW_READ_ONLY, false);
Gary Maia6c80b32016-09-30 16:34:55 -0700107
108 mUri = intent.getData();
109 final String authority = mUri.getAuthority();
110 final String type = getContentResolver().getType(mUri);
111 // Go straight to editor if we're passed a raw contact Uri.
112 if (ContactsContract.AUTHORITY.equals(authority) &&
113 RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
yaolu341d1042016-11-07 15:46:46 -0800114 Logger.logEditorEvent(
115 EditorEvent.EventType.SHOW_RAW_CONTACT_PICKER, /* numberRawContacts */ 0);
Gary Maia6c80b32016-09-30 16:34:55 -0700116 final long rawContactId = ContentUris.parseId(mUri);
Gary Mai5336e6e2016-10-23 14:17:03 -0700117 startEditorAndForwardExtras(getIntentForRawContact(rawContactId));
Gary Maia1721802016-11-01 17:55:31 -0700118 } else if (android.provider.Contacts.AUTHORITY.equals(authority)) {
119 // Fail if given a legacy URI.
120 FeedbackHelper.sendFeedback(this, TAG,
121 "Legacy Uri was passed to editor.", new IllegalArgumentException());
122 toastErrorAndFinish();
Gary Maia6c80b32016-09-30 16:34:55 -0700123 } else {
124 getLoaderManager().initLoader(LOADER_RAW_CONTACTS, null, mRawContactLoaderListener);
125 }
126 }
127
Gary Mai5336e6e2016-10-23 14:17:03 -0700128 @Override
129 public void onPickRawContact(long rawContactId) {
130 startEditorAndForwardExtras(getIntentForRawContact(rawContactId));
131 }
132
Gary Maia6c80b32016-09-30 16:34:55 -0700133 /**
Gary Maib9065dd2016-11-08 10:49:00 -0800134 * Once the load is finished, decide whether to show the dialog or load the editor directly.
135 */
136 private void onLoad() {
137 maybeTrimReadOnly();
138 setHasWritableAccount();
139 if (mShowReadOnly || (mResult.rawContacts.size() > 1 && mHasWritableAccount)) {
140 showDialog();
141 } else {
142 loadEditor();
143 }
144 }
145
146 /**
Gary Maia1721802016-11-01 17:55:31 -0700147 * If not configured to show read only raw contact, trim them from the result.
148 */
149 private void maybeTrimReadOnly() {
Gary Maib9065dd2016-11-08 10:49:00 -0800150 mResult.showReadOnly = mShowReadOnly;
151 if (mShowReadOnly) {
Gary Maia1721802016-11-01 17:55:31 -0700152 return;
153 }
Gary Maib9065dd2016-11-08 10:49:00 -0800154
Gary Maia1721802016-11-01 17:55:31 -0700155 mResult.trimReadOnly(AccountTypeManager.getInstance(this));
156 }
157
158 /**
Gary Maia6c80b32016-09-30 16:34:55 -0700159 * Start the dialog to pick the raw contact to edit.
160 */
161 private void showDialog() {
162 final FragmentManager fm = getFragmentManager();
Gary Maib9065dd2016-11-08 10:49:00 -0800163 final SplitContactConfirmationDialogFragment split =
164 (SplitContactConfirmationDialogFragment) fm
165 .findFragmentByTag(SplitContactConfirmationDialogFragment.TAG);
166 // If we were showing the split confirmation before show it again.
167 if (split != null && split.isAdded()) {
168 fm.beginTransaction().show(split).commitAllowingStateLoss();
Gary Maiea2f3572016-10-11 17:30:28 -0700169 return;
170 }
Gary Mai91e8d842016-11-17 18:06:02 -0800171 PickRawContactDialogFragment pick = (PickRawContactDialogFragment) fm
172 .findFragmentByTag(TAG_RAW_CONTACTS_DIALOG);
173 if (pick == null) {
174 pick = PickRawContactDialogFragment.getInstance(mResult);
175 final FragmentTransaction ft = fm.beginTransaction();
176 ft.add(pick, TAG_RAW_CONTACTS_DIALOG);
177 // commitAllowingStateLoss is safe in this activity because the fragment entirely
178 // depends on the result of the loader. Even if we lose the fragment because the
179 // activity was in the background, when it comes back onLoadFinished will be called
180 // again which will have all the state the picker needs. This situation should be
181 // very rare, since the load should be quick.
182 ft.commitAllowingStateLoss();
183 }
Gary Maia6c80b32016-09-30 16:34:55 -0700184 }
185
186 /**
Gary Mai5a00de32016-10-19 18:20:41 -0700187 * Starts the editor for the only writable raw contact in the cursor if one exists. Otherwise,
188 * the editor is started normally and handles creation of a new writable raw contact.
Gary Maia6c80b32016-09-30 16:34:55 -0700189 */
190 private void loadEditor() {
yaolu341d1042016-11-07 15:46:46 -0800191 Logger.logEditorEvent(
192 EditorEvent.EventType.SHOW_RAW_CONTACT_PICKER, /* numberRawContacts */ 0);
Gary Maia6c80b32016-09-30 16:34:55 -0700193 final Intent intent;
Gary Mai5a00de32016-10-19 18:20:41 -0700194 if (mHasWritableAccount) {
Gary Maia1721802016-11-01 17:55:31 -0700195 intent = getIntentForRawContact(mResult.rawContacts.get(mWritableAccountPosition).id);
Gary Maia6c80b32016-09-30 16:34:55 -0700196 } else {
Gary Mai5a00de32016-10-19 18:20:41 -0700197 // If the contact has only read-only raw contacts, we'll want to let the editor create
Gary Maia6c80b32016-09-30 16:34:55 -0700198 // the writable raw contact for it.
199 intent = EditorIntents.createEditContactIntent(this, mUri, mMaterialPalette, -1);
200 intent.setClass(this, ContactEditorActivity.class);
201 }
Gary Mai5336e6e2016-10-23 14:17:03 -0700202 startEditorAndForwardExtras(intent);
Gary Maia6c80b32016-09-30 16:34:55 -0700203 }
204
205 /**
Gary Mai5a00de32016-10-19 18:20:41 -0700206 * Determines if this contact has a writable account.
Gary Maia6c80b32016-09-30 16:34:55 -0700207 */
Gary Mai5a00de32016-10-19 18:20:41 -0700208 private void setHasWritableAccount() {
Gary Maia1721802016-11-01 17:55:31 -0700209 mWritableAccountPosition = mResult.getIndexOfFirstWritableAccount(
210 AccountTypeManager.getInstance(this));
211 mHasWritableAccount = mWritableAccountPosition != -1;
Gary Maia6c80b32016-09-30 16:34:55 -0700212 }
213
214 /**
215 * Returns an intent to load the editor for the given raw contact. Sets
216 * {@code FLAG_ACTIVITY_FORWARD_RESULT} in case the activity that started us expects a result.
217 * @param rawContactId Raw contact to edit
218 */
219 private Intent getIntentForRawContact(long rawContactId) {
220 final Intent intent = EditorIntents.createEditContactIntentForRawContact(
221 this, mUri, rawContactId, mMaterialPalette);
222 intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
223 return intent;
224 }
Gary Mai5336e6e2016-10-23 14:17:03 -0700225
226 /**
227 * Starts the given intent within the app, attaching any extras to it that were passed to us.
228 */
229 private void startEditorAndForwardExtras(Intent intent) {
230 final Bundle extras = getIntent().getExtras();
231 if (extras != null) {
232 intent.putExtras(extras);
233 }
234 ImplicitIntentsUtil.startActivityInApp(this, intent);
Gary Maib2bec432016-11-21 11:05:30 -0800235 finish();
Gary Mai5336e6e2016-10-23 14:17:03 -0700236 }
Gary Maia1721802016-11-01 17:55:31 -0700237
238 private void toastErrorAndFinish() {
239 Toast.makeText(ContactEditorSpringBoardActivity.this,
240 R.string.editor_failed_to_load, Toast.LENGTH_SHORT).show();
241 setResult(RESULT_CANCELED, null);
242 finish();
243 }
Gary Maib9065dd2016-11-08 10:49:00 -0800244
245 @Override
246 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
247 // Ignore failed requests
248 if (resultCode != Activity.RESULT_OK) {
249 finish();
250 }
251 if (data != null) {
252 final Intent intent = ContactSaveService.createJoinContactsIntent(
253 this, mResult.contactId, ContentUris.parseId(data.getData()),
254 QuickContactActivity.class, Intent.ACTION_VIEW);
255 startService(intent);
256 finish();
257 }
258 }
259
260 @Override
261 public void onSplitContactConfirmed(boolean hasPendingChanges) {
262 final long[][] rawContactIds = getRawContactIds();
263 final Intent intent = ContactSaveService.createHardSplitContactIntent(this, rawContactIds);
264 startService(intent);
265 finish();
266 }
267
268 @Override
269 public void onSplitContactCanceled() {
270 finish();
271 }
272
Gary Maia84f1d42016-11-29 11:16:27 -0800273 @Override
274 protected void onSaveInstanceState(Bundle outState) {
275 super.onSaveInstanceState(outState);
276 outState.putParcelable(KEY_RAW_CONTACTS_METADATA, mResult);
277 }
278
279 @Override
280 protected void onRestoreInstanceState(Bundle savedInstanceState) {
281 super.onRestoreInstanceState(savedInstanceState);
282 mResult = savedInstanceState.getParcelable(KEY_RAW_CONTACTS_METADATA);
283 }
284
Gary Maib9065dd2016-11-08 10:49:00 -0800285 private long[][] getRawContactIds() {
286 final long[][] result = new long[mResult.rawContacts.size()][1];
287 for (int i = 0; i < mResult.rawContacts.size(); i++) {
288 result[i][0] = mResult.rawContacts.get(i).id;
289 }
290 return result;
291 }
Gary Maia6c80b32016-09-30 16:34:55 -0700292}