blob: 0c60203cdaa3474ccb513cdeb4fd9bc1d22ed3bd [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;
19import com.android.contacts.common.activity.RequestPermissionsActivity;
yaolu341d1042016-11-07 15:46:46 -080020import com.android.contacts.common.logging.EditorEvent;
21import com.android.contacts.common.logging.Logger;
Gary Maia6c80b32016-09-30 16:34:55 -070022import com.android.contacts.common.model.AccountTypeManager;
Gary Maia6c80b32016-09-30 16:34:55 -070023import com.android.contacts.common.util.ImplicitIntentsUtil;
24import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
25import com.android.contacts.editor.ContactEditorFragment;
26import com.android.contacts.editor.EditorIntents;
27import com.android.contacts.editor.PickRawContactDialogFragment;
28import com.android.contacts.editor.PickRawContactLoader;
Gary Maia1721802016-11-01 17:55:31 -070029import com.android.contacts.editor.PickRawContactLoader.RawContactsMetadata;
Gary Maib9065dd2016-11-08 10:49:00 -080030import com.android.contacts.editor.SplitContactConfirmationDialogFragment;
31import com.android.contacts.quickcontact.QuickContactActivity;
Gary Maia1721802016-11-01 17:55:31 -070032import com.android.contactsbind.FeedbackHelper;
Gary Maia6c80b32016-09-30 16:34:55 -070033
34/**
35 * Transparent springboard activity that hosts a dialog to select a raw contact to edit.
Gary Maib9065dd2016-11-08 10:49:00 -080036 * All intents coming out from this activity have {@code FLAG_ACTIVITY_FORWARD_RESULT} set.
Gary Maia6c80b32016-09-30 16:34:55 -070037 */
Gary Mai5336e6e2016-10-23 14:17:03 -070038public class ContactEditorSpringBoardActivity extends AppCompatContactsActivity implements
Gary Maib9065dd2016-11-08 10:49:00 -080039 PickRawContactDialogFragment.PickRawContactListener,
40 SplitContactConfirmationDialogFragment.Listener {
41
Gary Maia6c80b32016-09-30 16:34:55 -070042 private static final String TAG = "EditorSpringBoard";
43 private static final String TAG_RAW_CONTACTS_DIALOG = "rawContactsDialog";
Gary Maia84f1d42016-11-29 11:16:27 -080044 private static final String KEY_RAW_CONTACTS_METADATA = "rawContactsMetadata";
Gary Maia6c80b32016-09-30 16:34:55 -070045 private static final int LOADER_RAW_CONTACTS = 1;
46
Gary Maia1721802016-11-01 17:55:31 -070047 public static final String EXTRA_SHOW_READ_ONLY = "showReadOnly";
48
Gary Maia6c80b32016-09-30 16:34:55 -070049 private Uri mUri;
Gary Maia1721802016-11-01 17:55:31 -070050 private RawContactsMetadata mResult;
Gary Maia6c80b32016-09-30 16:34:55 -070051 private MaterialPalette mMaterialPalette;
Gary Mai5a00de32016-10-19 18:20:41 -070052 private boolean mHasWritableAccount;
Gary Maib9065dd2016-11-08 10:49:00 -080053 private boolean mShowReadOnly;
Gary Mai5a00de32016-10-19 18:20:41 -070054 private int mWritableAccountPosition;
Gary Maia6c80b32016-09-30 16:34:55 -070055
56 /**
57 * The contact data loader listener.
58 */
Gary Maia1721802016-11-01 17:55:31 -070059 protected final LoaderManager.LoaderCallbacks<RawContactsMetadata> mRawContactLoaderListener =
60 new LoaderManager.LoaderCallbacks<RawContactsMetadata>() {
Gary Maia6c80b32016-09-30 16:34:55 -070061
62 @Override
Gary Maia1721802016-11-01 17:55:31 -070063 public Loader<RawContactsMetadata> onCreateLoader(int id, Bundle args) {
Gary Maia6c80b32016-09-30 16:34:55 -070064 return new PickRawContactLoader(ContactEditorSpringBoardActivity.this, mUri);
65 }
66
67 @Override
Gary Maia1721802016-11-01 17:55:31 -070068 public void onLoadFinished(Loader<RawContactsMetadata> loader,
69 RawContactsMetadata result) {
70 if (result == null) {
71 toastErrorAndFinish();
Gary Maia6c80b32016-09-30 16:34:55 -070072 return;
73 }
Gary Maia1721802016-11-01 17:55:31 -070074 mResult = result;
Gary Maib9065dd2016-11-08 10:49:00 -080075 onLoad();
Gary Maia6c80b32016-09-30 16:34:55 -070076 }
77
78 @Override
Gary Maia1721802016-11-01 17:55:31 -070079 public void onLoaderReset(Loader<RawContactsMetadata> loader) {
Gary Maia6c80b32016-09-30 16:34:55 -070080 }
81 };
82
83
84 @Override
85 protected void onCreate(Bundle savedInstanceState) {
86 super.onCreate(savedInstanceState);
87
88 if (RequestPermissionsActivity.startPermissionActivity(this)) {
89 return;
90 }
91
92 final Intent intent = getIntent();
93 final String action = intent.getAction();
94
95 if (!Intent.ACTION_EDIT.equals(action)) {
96 finish();
97 return;
98 }
99 // Just for shorter variable names.
100 final String primary = ContactEditorFragment.INTENT_EXTRA_MATERIAL_PALETTE_PRIMARY_COLOR;
101 final String secondary =
102 ContactEditorFragment.INTENT_EXTRA_MATERIAL_PALETTE_SECONDARY_COLOR;
103 if (intent.hasExtra(primary) && intent.hasExtra(secondary)) {
104 mMaterialPalette = new MaterialPalette(intent.getIntExtra(primary, -1),
105 intent.getIntExtra(secondary, -1));
106 }
Gary Maib9065dd2016-11-08 10:49:00 -0800107 mShowReadOnly = intent.getBooleanExtra(EXTRA_SHOW_READ_ONLY, false);
Gary Maia6c80b32016-09-30 16:34:55 -0700108
109 mUri = intent.getData();
110 final String authority = mUri.getAuthority();
111 final String type = getContentResolver().getType(mUri);
112 // Go straight to editor if we're passed a raw contact Uri.
113 if (ContactsContract.AUTHORITY.equals(authority) &&
114 RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
yaolu341d1042016-11-07 15:46:46 -0800115 Logger.logEditorEvent(
116 EditorEvent.EventType.SHOW_RAW_CONTACT_PICKER, /* numberRawContacts */ 0);
Gary Maia6c80b32016-09-30 16:34:55 -0700117 final long rawContactId = ContentUris.parseId(mUri);
Gary Mai5336e6e2016-10-23 14:17:03 -0700118 startEditorAndForwardExtras(getIntentForRawContact(rawContactId));
Gary Maia1721802016-11-01 17:55:31 -0700119 } else if (android.provider.Contacts.AUTHORITY.equals(authority)) {
120 // Fail if given a legacy URI.
121 FeedbackHelper.sendFeedback(this, TAG,
122 "Legacy Uri was passed to editor.", new IllegalArgumentException());
123 toastErrorAndFinish();
Gary Maia6c80b32016-09-30 16:34:55 -0700124 } else {
125 getLoaderManager().initLoader(LOADER_RAW_CONTACTS, null, mRawContactLoaderListener);
126 }
127 }
128
Gary Mai5336e6e2016-10-23 14:17:03 -0700129 @Override
130 public void onPickRawContact(long rawContactId) {
131 startEditorAndForwardExtras(getIntentForRawContact(rawContactId));
132 }
133
Gary Maia6c80b32016-09-30 16:34:55 -0700134 /**
Gary Maib9065dd2016-11-08 10:49:00 -0800135 * Once the load is finished, decide whether to show the dialog or load the editor directly.
136 */
137 private void onLoad() {
138 maybeTrimReadOnly();
139 setHasWritableAccount();
140 if (mShowReadOnly || (mResult.rawContacts.size() > 1 && mHasWritableAccount)) {
141 showDialog();
142 } else {
143 loadEditor();
144 }
145 }
146
147 /**
Gary Maia1721802016-11-01 17:55:31 -0700148 * If not configured to show read only raw contact, trim them from the result.
149 */
150 private void maybeTrimReadOnly() {
Gary Maib9065dd2016-11-08 10:49:00 -0800151 mResult.showReadOnly = mShowReadOnly;
152 if (mShowReadOnly) {
Gary Maia1721802016-11-01 17:55:31 -0700153 return;
154 }
Gary Maib9065dd2016-11-08 10:49:00 -0800155
Gary Maia1721802016-11-01 17:55:31 -0700156 mResult.trimReadOnly(AccountTypeManager.getInstance(this));
157 }
158
159 /**
Gary Maia6c80b32016-09-30 16:34:55 -0700160 * Start the dialog to pick the raw contact to edit.
161 */
162 private void showDialog() {
163 final FragmentManager fm = getFragmentManager();
Gary Maib9065dd2016-11-08 10:49:00 -0800164 final SplitContactConfirmationDialogFragment split =
165 (SplitContactConfirmationDialogFragment) fm
166 .findFragmentByTag(SplitContactConfirmationDialogFragment.TAG);
167 // If we were showing the split confirmation before show it again.
168 if (split != null && split.isAdded()) {
169 fm.beginTransaction().show(split).commitAllowingStateLoss();
Gary Maiea2f3572016-10-11 17:30:28 -0700170 return;
171 }
Gary Mai91e8d842016-11-17 18:06:02 -0800172 PickRawContactDialogFragment pick = (PickRawContactDialogFragment) fm
173 .findFragmentByTag(TAG_RAW_CONTACTS_DIALOG);
174 if (pick == null) {
175 pick = PickRawContactDialogFragment.getInstance(mResult);
176 final FragmentTransaction ft = fm.beginTransaction();
177 ft.add(pick, TAG_RAW_CONTACTS_DIALOG);
178 // commitAllowingStateLoss is safe in this activity because the fragment entirely
179 // depends on the result of the loader. Even if we lose the fragment because the
180 // activity was in the background, when it comes back onLoadFinished will be called
181 // again which will have all the state the picker needs. This situation should be
182 // very rare, since the load should be quick.
183 ft.commitAllowingStateLoss();
184 }
Gary Maia6c80b32016-09-30 16:34:55 -0700185 }
186
187 /**
Gary Mai5a00de32016-10-19 18:20:41 -0700188 * Starts the editor for the only writable raw contact in the cursor if one exists. Otherwise,
189 * the editor is started normally and handles creation of a new writable raw contact.
Gary Maia6c80b32016-09-30 16:34:55 -0700190 */
191 private void loadEditor() {
yaolu341d1042016-11-07 15:46:46 -0800192 Logger.logEditorEvent(
193 EditorEvent.EventType.SHOW_RAW_CONTACT_PICKER, /* numberRawContacts */ 0);
Gary Maia6c80b32016-09-30 16:34:55 -0700194 final Intent intent;
Gary Mai5a00de32016-10-19 18:20:41 -0700195 if (mHasWritableAccount) {
Gary Maia1721802016-11-01 17:55:31 -0700196 intent = getIntentForRawContact(mResult.rawContacts.get(mWritableAccountPosition).id);
Gary Maia6c80b32016-09-30 16:34:55 -0700197 } else {
Gary Mai5a00de32016-10-19 18:20:41 -0700198 // If the contact has only read-only raw contacts, we'll want to let the editor create
Gary Maia6c80b32016-09-30 16:34:55 -0700199 // the writable raw contact for it.
200 intent = EditorIntents.createEditContactIntent(this, mUri, mMaterialPalette, -1);
201 intent.setClass(this, ContactEditorActivity.class);
202 }
Gary Mai5336e6e2016-10-23 14:17:03 -0700203 startEditorAndForwardExtras(intent);
Gary Maia6c80b32016-09-30 16:34:55 -0700204 }
205
206 /**
Gary Mai5a00de32016-10-19 18:20:41 -0700207 * Determines if this contact has a writable account.
Gary Maia6c80b32016-09-30 16:34:55 -0700208 */
Gary Mai5a00de32016-10-19 18:20:41 -0700209 private void setHasWritableAccount() {
Gary Maia1721802016-11-01 17:55:31 -0700210 mWritableAccountPosition = mResult.getIndexOfFirstWritableAccount(
211 AccountTypeManager.getInstance(this));
212 mHasWritableAccount = mWritableAccountPosition != -1;
Gary Maia6c80b32016-09-30 16:34:55 -0700213 }
214
215 /**
216 * Returns an intent to load the editor for the given raw contact. Sets
217 * {@code FLAG_ACTIVITY_FORWARD_RESULT} in case the activity that started us expects a result.
218 * @param rawContactId Raw contact to edit
219 */
220 private Intent getIntentForRawContact(long rawContactId) {
221 final Intent intent = EditorIntents.createEditContactIntentForRawContact(
222 this, mUri, rawContactId, mMaterialPalette);
223 intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
224 return intent;
225 }
Gary Mai5336e6e2016-10-23 14:17:03 -0700226
227 /**
228 * Starts the given intent within the app, attaching any extras to it that were passed to us.
229 */
230 private void startEditorAndForwardExtras(Intent intent) {
231 final Bundle extras = getIntent().getExtras();
232 if (extras != null) {
233 intent.putExtras(extras);
234 }
235 ImplicitIntentsUtil.startActivityInApp(this, intent);
Gary Maib2bec432016-11-21 11:05:30 -0800236 finish();
Gary Mai5336e6e2016-10-23 14:17:03 -0700237 }
Gary Maia1721802016-11-01 17:55:31 -0700238
239 private void toastErrorAndFinish() {
240 Toast.makeText(ContactEditorSpringBoardActivity.this,
241 R.string.editor_failed_to_load, Toast.LENGTH_SHORT).show();
242 setResult(RESULT_CANCELED, null);
243 finish();
244 }
Gary Maib9065dd2016-11-08 10:49:00 -0800245
246 @Override
247 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
248 // Ignore failed requests
249 if (resultCode != Activity.RESULT_OK) {
250 finish();
251 }
252 if (data != null) {
253 final Intent intent = ContactSaveService.createJoinContactsIntent(
254 this, mResult.contactId, ContentUris.parseId(data.getData()),
255 QuickContactActivity.class, Intent.ACTION_VIEW);
256 startService(intent);
257 finish();
258 }
259 }
260
261 @Override
262 public void onSplitContactConfirmed(boolean hasPendingChanges) {
263 final long[][] rawContactIds = getRawContactIds();
264 final Intent intent = ContactSaveService.createHardSplitContactIntent(this, rawContactIds);
265 startService(intent);
266 finish();
267 }
268
269 @Override
270 public void onSplitContactCanceled() {
271 finish();
272 }
273
Gary Maia84f1d42016-11-29 11:16:27 -0800274 @Override
275 protected void onSaveInstanceState(Bundle outState) {
276 super.onSaveInstanceState(outState);
277 outState.putParcelable(KEY_RAW_CONTACTS_METADATA, mResult);
278 }
279
280 @Override
281 protected void onRestoreInstanceState(Bundle savedInstanceState) {
282 super.onRestoreInstanceState(savedInstanceState);
283 mResult = savedInstanceState.getParcelable(KEY_RAW_CONTACTS_METADATA);
284 }
285
Gary Maib9065dd2016-11-08 10:49:00 -0800286 private long[][] getRawContactIds() {
287 final long[][] result = new long[mResult.rawContacts.size()][1];
288 for (int i = 0; i < mResult.rawContacts.size(); i++) {
289 result[i][0] = mResult.rawContacts.get(i).id;
290 }
291 return result;
292 }
Gary Maia6c80b32016-09-30 16:34:55 -0700293}