blob: 5b80b04631773d03348d3175029daa181faf707a [file] [log] [blame]
Makoto Onuki558669d2011-09-22 18:09:28 -07001/*
2 * Copyright (C) 2011 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.editor;
18
Makoto Onuki558669d2011-09-22 18:09:28 -070019import android.accounts.Account;
20import android.accounts.AccountManager;
21import android.app.Activity;
Walter Jang7b0970f2016-09-01 10:40:19 -070022import android.content.ContentUris;
Makoto Onuki558669d2011-09-22 18:09:28 -070023import android.content.Context;
24import android.content.Intent;
Walter Jang7b0970f2016-09-01 10:40:19 -070025import android.net.Uri;
26import android.provider.ContactsContract;
Makoto Onuki558669d2011-09-22 18:09:28 -070027import android.text.TextUtils;
28
Chiao Cheng0d5588d2012-11-26 15:34:14 -080029import com.android.contacts.common.model.AccountTypeManager;
Chiao Cheng428f0082012-11-13 18:38:56 -080030import com.android.contacts.common.model.account.AccountType;
31import com.android.contacts.common.model.account.AccountWithDataSet;
Marcus Hagerott949d4e82016-09-20 13:23:05 -070032import com.android.contacts.common.preference.ContactsPreferences;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070033import com.google.common.annotations.VisibleForTesting;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070034import com.google.common.collect.Sets;
35
Makoto Onuki558669d2011-09-22 18:09:28 -070036import java.util.ArrayList;
37import java.util.List;
38import java.util.Set;
39
40/**
41 * Utility methods for the "account changed" notification in the new contact creation flow.
Makoto Onuki558669d2011-09-22 18:09:28 -070042 */
43public class ContactEditorUtils {
44 private static final String TAG = "ContactEditorUtils";
45
Marcus Hagerott949d4e82016-09-20 13:23:05 -070046 private final ContactsPreferences mContactsPrefs;
Makoto Onuki558669d2011-09-22 18:09:28 -070047 private final AccountTypeManager mAccountTypes;
48
49 private ContactEditorUtils(Context context) {
50 this(context, AccountTypeManager.getInstance(context));
51 }
52
53 @VisibleForTesting
54 ContactEditorUtils(Context context, AccountTypeManager accountTypes) {
Marcus Hagerott949d4e82016-09-20 13:23:05 -070055 mContactsPrefs = new ContactsPreferences(context);
Makoto Onuki558669d2011-09-22 18:09:28 -070056 mAccountTypes = accountTypes;
57 }
58
Marcus Hagerott949d4e82016-09-20 13:23:05 -070059 public static ContactEditorUtils create(Context context) {
60 return new ContactEditorUtils(context.getApplicationContext());
Makoto Onuki558669d2011-09-22 18:09:28 -070061 }
62
Walter Jang7b0970f2016-09-01 10:40:19 -070063 /**
64 * Returns a legacy version of the given contactLookupUri if a legacy Uri was originally
65 * passed to the contact editor.
66 *
67 * @param contactLookupUri The Uri to possibly convert to legacy format.
68 * @param requestLookupUri The lookup Uri originally passed to the contact editor
69 * (via Intent data), may be null.
70 */
71 static Uri maybeConvertToLegacyLookupUri(Context context, Uri contactLookupUri,
72 Uri requestLookupUri) {
73 final String legacyAuthority = "contacts";
74 final String requestAuthority = requestLookupUri == null
75 ? null : requestLookupUri.getAuthority();
76 if (legacyAuthority.equals(requestAuthority)) {
77 // Build a legacy Uri if that is what was requested by caller
78 final long contactId = ContentUris.parseId(ContactsContract.Contacts.lookupContact(
79 context.getContentResolver(), contactLookupUri));
80 final Uri legacyContentUri = Uri.parse("content://contacts/people");
81 return ContentUris.withAppendedId(legacyContentUri, contactId);
82 }
83 // Otherwise pass back a lookup-style Uri
84 return contactLookupUri;
85 }
86
Makoto Onuki558669d2011-09-22 18:09:28 -070087 void cleanupForTest() {
Marcus Hagerott949d4e82016-09-20 13:23:05 -070088 mContactsPrefs.clearDefaultAccount();
Makoto Onuki558669d2011-09-22 18:09:28 -070089 }
90
Makoto Onuki131e6ac2011-10-04 19:09:54 -070091 void removeDefaultAccountForTest() {
Marcus Hagerott949d4e82016-09-20 13:23:05 -070092 mContactsPrefs.clearDefaultAccount();
Makoto Onuki131e6ac2011-10-04 19:09:54 -070093 }
94
Makoto Onuki558669d2011-09-22 18:09:28 -070095 private List<AccountWithDataSet> getWritableAccounts() {
96 return mAccountTypes.getAccounts(true);
97 }
98
99 /**
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700100 * Saves the default account, which can later be obtained with {@link #getOnlyOrDefaultAccount}.
Makoto Onuki558669d2011-09-22 18:09:28 -0700101 *
102 * This should be called when saving a newly created contact.
103 *
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700104 * @param defaultAccount the account used to save a newly created contact.
Makoto Onuki558669d2011-09-22 18:09:28 -0700105 */
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700106 public void saveDefaultAccount(AccountWithDataSet defaultAccount) {
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700107 if (defaultAccount == null) {
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700108 mContactsPrefs.clearDefaultAccount();
Makoto Onuki131e6ac2011-10-04 19:09:54 -0700109 } else {
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700110 mContactsPrefs.setDefaultAccount(defaultAccount);
Makoto Onuki131e6ac2011-10-04 19:09:54 -0700111 }
Makoto Onuki558669d2011-09-22 18:09:28 -0700112 }
113
114 /**
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700115 * @return the first account if there is only a single account or the default account saved
116 * with {@link #saveDefaultAccount}.
Makoto Onuki558669d2011-09-22 18:09:28 -0700117 *
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700118 * A null return value indicates that there is multiple accounts and a default hasn't been set
Makoto Onuki558669d2011-09-22 18:09:28 -0700119 *
120 * Also note that the returned account may have been removed already.
121 */
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700122 public AccountWithDataSet getOnlyOrDefaultAccount() {
Tingting Wang4abdee92015-11-24 11:50:21 -0800123 final List<AccountWithDataSet> currentWritableAccounts = getWritableAccounts();
124 if (currentWritableAccounts.size() == 1) {
125 return currentWritableAccounts.get(0);
126 }
127
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700128 return mContactsPrefs.getDefaultAccount();
Makoto Onuki558669d2011-09-22 18:09:28 -0700129 }
130
Makoto Onuki558669d2011-09-22 18:09:28 -0700131 public boolean shouldShowAccountChangedNotification() {
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700132 return mContactsPrefs.shouldShowAccountChangedNotification(getWritableAccounts());
Makoto Onuki558669d2011-09-22 18:09:28 -0700133 }
134
Gary Mai3107b252016-11-02 18:26:07 -0700135 /**
136 * Sets the only non-device account to be default if it is not already.
137 */
138 public void maybeUpdateDefaultAccount() {
139 final List<AccountWithDataSet> currentWritableAccounts = getWritableAccounts();
140 if (currentWritableAccounts.size() == 1) {
141 final AccountWithDataSet onlyAccount = currentWritableAccounts.get(0);
142 if (!onlyAccount.isNullAccount()
143 && !onlyAccount.equals(mContactsPrefs.getDefaultAccount())) {
144 mContactsPrefs.setDefaultAccount(onlyAccount);
145 }
146 }
147 }
148
Makoto Onuki558669d2011-09-22 18:09:28 -0700149 @VisibleForTesting
150 String[] getWritableAccountTypeStrings() {
151 final Set<String> types = Sets.newHashSet();
152 for (AccountType type : mAccountTypes.getAccountTypes(true)) {
153 types.add(type.accountType);
154 }
155 return types.toArray(new String[types.size()]);
156 }
157
158 /**
159 * Create an {@link Intent} to start "add new account" setup wizard. Selectable account
160 * types will be limited to ones that supports editing contacts.
161 *
162 * Use {@link Activity#startActivityForResult} or
163 * {@link android.app.Fragment#startActivityForResult} to start the wizard, and
164 * {@link Activity#onActivityResult} or {@link android.app.Fragment#onActivityResult} to
165 * get the result.
166 */
Makoto Onuki558669d2011-09-22 18:09:28 -0700167 public Intent createAddWritableAccountIntent() {
168 return AccountManager.newChooseAccountIntent(
169 null, // selectedAccount
170 new ArrayList<Account>(), // allowableAccounts
171 getWritableAccountTypeStrings(), // allowableAccountTypes
172 false, // alwaysPromptForAccount
173 null, // descriptionOverrideText
174 null, // addAccountAuthTokenType
175 null, // addAccountRequiredFeatures
176 null // addAccountOptions
177 );
178 }
179
180 /**
181 * Parses a result from {@link #createAddWritableAccountIntent} and returns the created
182 * {@link Account}, or null if the user has canceled the wizard. Pass the {@code resultCode}
183 * and {@code data} parameters passed to {@link Activity#onActivityResult} or
184 * {@link android.app.Fragment#onActivityResult}.
185 *
186 * Note although the return type is {@link AccountWithDataSet}, return values from this method
187 * will never have {@link AccountWithDataSet#dataSet} set, as there's no way to create an
188 * extension package account from setup wizard.
189 */
Makoto Onuki558669d2011-09-22 18:09:28 -0700190 public AccountWithDataSet getCreatedAccount(int resultCode, Intent resultData) {
191 // Javadoc doesn't say anything about resultCode but that the data intent will be non null
192 // on success.
193 if (resultData == null) return null;
194
195 final String accountType = resultData.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
196 final String accountName = resultData.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
197
198 // Just in case
199 if (TextUtils.isEmpty(accountType) || TextUtils.isEmpty(accountName)) return null;
200
201 return new AccountWithDataSet(accountName, accountType, null);
202 }
203}