Chiao Cheng | ddd4e82 | 2012-12-06 12:18:01 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 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 | |
| 17 | package com.android.contacts.editor; |
| 18 | |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 19 | import static android.provider.ContactsContract.CommonDataKinds.GroupMembership; |
| 20 | import static android.provider.ContactsContract.CommonDataKinds.StructuredName; |
| 21 | |
| 22 | import static com.android.contacts.util.MaterialColorMapUtils.getDefaultPrimaryAndSecondaryColors; |
| 23 | |
Walter Jang | 2d3f31c | 2015-06-18 23:15:31 -0700 | [diff] [blame] | 24 | import android.content.Context; |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 25 | import android.content.res.Resources; |
| 26 | import android.graphics.Bitmap; |
| 27 | import android.graphics.BitmapFactory; |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 28 | import android.graphics.drawable.Drawable; |
Marcus Hagerott | fac695a | 2016-08-24 17:02:40 -0700 | [diff] [blame] | 29 | import android.media.RingtoneManager; |
| 30 | import android.net.Uri; |
| 31 | import android.os.Build; |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 32 | import android.provider.ContactsContract.CommonDataKinds.Email; |
| 33 | import android.provider.ContactsContract.CommonDataKinds.Event; |
| 34 | import android.provider.ContactsContract.CommonDataKinds.Im; |
| 35 | import android.provider.ContactsContract.CommonDataKinds.Note; |
| 36 | import android.provider.ContactsContract.CommonDataKinds.Organization; |
| 37 | import android.provider.ContactsContract.CommonDataKinds.Phone; |
| 38 | import android.provider.ContactsContract.CommonDataKinds.Photo; |
| 39 | import android.provider.ContactsContract.CommonDataKinds.Relation; |
| 40 | import android.provider.ContactsContract.CommonDataKinds.SipAddress; |
| 41 | import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; |
| 42 | import android.provider.ContactsContract.CommonDataKinds.Website; |
Aravind Sreekumar | 7121285 | 2018-04-06 15:47:45 -0700 | [diff] [blame] | 43 | import androidx.core.content.res.ResourcesCompat; |
Walter Jang | 2d3f31c | 2015-06-18 23:15:31 -0700 | [diff] [blame] | 44 | import android.text.TextUtils; |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 45 | import android.widget.ImageView; |
| 46 | |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 47 | import com.android.contacts.ContactPhotoManager; |
| 48 | import com.android.contacts.ContactPhotoManager.DefaultImageProvider; |
| 49 | import com.android.contacts.ContactPhotoManager.DefaultImageRequest; |
| 50 | import com.android.contacts.ContactsUtils; |
Chiao Cheng | ddd4e82 | 2012-12-06 12:18:01 -0800 | [diff] [blame] | 51 | import com.android.contacts.R; |
Gary Mai | 69c182a | 2016-12-05 13:07:03 -0800 | [diff] [blame] | 52 | import com.android.contacts.model.ValuesDelta; |
Gary Mai | 69c182a | 2016-12-05 13:07:03 -0800 | [diff] [blame] | 53 | import com.android.contacts.model.account.AccountDisplayInfo; |
Marcus Hagerott | 4bd50d6 | 2016-12-15 15:52:22 -0800 | [diff] [blame] | 54 | import com.android.contacts.model.account.AccountInfo; |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 55 | import com.android.contacts.model.dataitem.DataKind; |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 56 | import com.android.contacts.util.ContactPhotoUtils; |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 57 | import com.android.contacts.util.MaterialColorMapUtils.MaterialPalette; |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 58 | import com.android.contacts.widget.QuickContactImageView; |
Gary Mai | 0a49afa | 2016-12-05 15:53:58 -0800 | [diff] [blame] | 59 | |
Chiao Cheng | ddd4e82 | 2012-12-06 12:18:01 -0800 | [diff] [blame] | 60 | import com.google.common.collect.Maps; |
| 61 | |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 62 | import java.io.FileNotFoundException; |
Chiao Cheng | ddd4e82 | 2012-12-06 12:18:01 -0800 | [diff] [blame] | 63 | import java.util.HashMap; |
| 64 | |
| 65 | /** |
| 66 | * Utility methods for creating contact editor. |
| 67 | */ |
| 68 | public class EditorUiUtils { |
| 69 | |
| 70 | // Maps DataKind.mimeType to editor view layouts. |
| 71 | private static final HashMap<String, Integer> mimetypeLayoutMap = Maps.newHashMap(); |
| 72 | static { |
| 73 | // Generally there should be a layout mapped to each existing DataKind mimetype but lots of |
| 74 | // them use the default text_fields_editor_view which we return as default so they don't |
| 75 | // need to be mapped. |
| 76 | // |
| 77 | // Other possible mime mappings are: |
| 78 | // DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME |
| 79 | // Nickname.CONTENT_ITEM_TYPE |
| 80 | // Email.CONTENT_ITEM_TYPE |
| 81 | // StructuredPostal.CONTENT_ITEM_TYPE |
| 82 | // Im.CONTENT_ITEM_TYPE |
| 83 | // Note.CONTENT_ITEM_TYPE |
| 84 | // Organization.CONTENT_ITEM_TYPE |
| 85 | // Phone.CONTENT_ITEM_TYPE |
| 86 | // SipAddress.CONTENT_ITEM_TYPE |
| 87 | // Website.CONTENT_ITEM_TYPE |
| 88 | // Relation.CONTENT_ITEM_TYPE |
| 89 | // |
| 90 | // Un-supported mime types need to mapped with -1. |
Chiao Cheng | ddd4e82 | 2012-12-06 12:18:01 -0800 | [diff] [blame] | 91 | mimetypeLayoutMap.put(StructuredName.CONTENT_ITEM_TYPE, |
| 92 | R.layout.structured_name_editor_view); |
| 93 | mimetypeLayoutMap.put(GroupMembership.CONTENT_ITEM_TYPE, -1); |
| 94 | mimetypeLayoutMap.put(Photo.CONTENT_ITEM_TYPE, -1); |
| 95 | mimetypeLayoutMap.put(Event.CONTENT_ITEM_TYPE, R.layout.event_field_editor_view); |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Fetches a layout for a given mimetype. |
| 100 | * |
| 101 | * @param mimetype The mime type (e.g. StructuredName.CONTENT_ITEM_TYPE) |
| 102 | * @return The layout resource id. |
| 103 | */ |
| 104 | public static int getLayoutResourceId(String mimetype) { |
| 105 | final Integer id = mimetypeLayoutMap.get(mimetype); |
| 106 | if (id == null) { |
| 107 | return R.layout.text_fields_editor_view; |
| 108 | } |
| 109 | return id; |
| 110 | } |
Walter Jang | 2d3f31c | 2015-06-18 23:15:31 -0700 | [diff] [blame] | 111 | |
Marcus Hagerott | fac695a | 2016-08-24 17:02:40 -0700 | [diff] [blame] | 112 | |
| 113 | public static String getAccountHeaderLabelForMyProfile(Context context, |
Marcus Hagerott | 4bd50d6 | 2016-12-15 15:52:22 -0800 | [diff] [blame] | 114 | AccountInfo accountInfo) { |
| 115 | if (accountInfo.isDeviceAccount()) { |
Marcus Hagerott | fac695a | 2016-08-24 17:02:40 -0700 | [diff] [blame] | 116 | return context.getString(R.string.local_profile_title); |
| 117 | } else { |
| 118 | return context.getString(R.string.external_profile_title, |
Marcus Hagerott | 4bd50d6 | 2016-12-15 15:52:22 -0800 | [diff] [blame] | 119 | accountInfo.getTypeLabel()); |
Walter Jang | c4cecc7 | 2015-06-25 10:45:50 -0700 | [diff] [blame] | 120 | } |
Walter Jang | be5e1b1 | 2015-10-17 11:38:29 -0700 | [diff] [blame] | 121 | } |
Walter Jang | c4cecc7 | 2015-06-25 10:45:50 -0700 | [diff] [blame] | 122 | |
Marcus Hagerott | fac695a | 2016-08-24 17:02:40 -0700 | [diff] [blame] | 123 | public static String getAccountTypeHeaderLabel(Context context, AccountDisplayInfo |
| 124 | displayableAccount) { |
| 125 | if (displayableAccount.isDeviceAccount()) { |
| 126 | // Do nothing. Type label should be "Device" |
| 127 | return displayableAccount.getTypeLabel().toString(); |
| 128 | } else if (displayableAccount.isGoogleAccount()) { |
| 129 | return context.getString(R.string.google_account_type_format, |
| 130 | displayableAccount.getTypeLabel()); |
Wenyi Wang | 541743c | 2016-06-30 12:24:39 -0700 | [diff] [blame] | 131 | } else { |
Marcus Hagerott | fac695a | 2016-08-24 17:02:40 -0700 | [diff] [blame] | 132 | return context.getString(R.string.account_type_format, |
| 133 | displayableAccount.getTypeLabel()); |
Walter Jang | defc69c | 2015-08-25 16:46:43 -0700 | [diff] [blame] | 134 | } |
Walter Jang | 2d3f31c | 2015-06-18 23:15:31 -0700 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | /** |
| 138 | * Returns a content description String for the container of the account information |
Marcus Hagerott | fac695a | 2016-08-24 17:02:40 -0700 | [diff] [blame] | 139 | * returned by {@link #getAccountTypeHeaderLabel(Context, AccountDisplayInfo)}. |
Walter Jang | 2d3f31c | 2015-06-18 23:15:31 -0700 | [diff] [blame] | 140 | */ |
| 141 | public static String getAccountInfoContentDescription(CharSequence accountName, |
| 142 | CharSequence accountType) { |
| 143 | final StringBuilder builder = new StringBuilder(); |
| 144 | if (!TextUtils.isEmpty(accountType)) { |
| 145 | builder.append(accountType).append('\n'); |
| 146 | } |
| 147 | if (!TextUtils.isEmpty(accountName)) { |
Walter Jang | be5e1b1 | 2015-10-17 11:38:29 -0700 | [diff] [blame] | 148 | builder.append(accountName); |
Walter Jang | 2d3f31c | 2015-06-18 23:15:31 -0700 | [diff] [blame] | 149 | } |
| 150 | return builder.toString(); |
| 151 | } |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 152 | |
| 153 | /** |
| 154 | * Return an icon that represents {@param mimeType}. |
| 155 | */ |
| 156 | public static Drawable getMimeTypeDrawable(Context context, String mimeType) { |
| 157 | switch (mimeType) { |
Walter Jang | 3e5ae0d | 2015-09-20 12:43:37 -0700 | [diff] [blame] | 158 | case StructuredName.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 159 | return ResourcesCompat.getDrawable(context.getResources(), |
| 160 | R.drawable.quantum_ic_person_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 161 | case StructuredPostal.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 162 | return ResourcesCompat.getDrawable(context.getResources(), |
| 163 | R.drawable.quantum_ic_place_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 164 | case SipAddress.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 165 | return ResourcesCompat.getDrawable(context.getResources(), |
| 166 | R.drawable.quantum_ic_dialer_sip_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 167 | case Phone.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 168 | return ResourcesCompat.getDrawable(context.getResources(), |
| 169 | R.drawable.quantum_ic_phone_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 170 | case Im.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 171 | return ResourcesCompat.getDrawable(context.getResources(), |
| 172 | R.drawable.quantum_ic_message_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 173 | case Event.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 174 | return ResourcesCompat.getDrawable(context.getResources(), |
| 175 | R.drawable.quantum_ic_event_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 176 | case Email.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 177 | return ResourcesCompat.getDrawable(context.getResources(), |
| 178 | R.drawable.quantum_ic_email_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 179 | case Website.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 180 | return ResourcesCompat.getDrawable(context.getResources(), |
| 181 | R.drawable.quantum_ic_public_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 182 | case Photo.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 183 | return ResourcesCompat.getDrawable(context.getResources(), |
| 184 | R.drawable.quantum_ic_camera_alt_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 185 | case GroupMembership.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 186 | return ResourcesCompat.getDrawable(context.getResources(), |
| 187 | R.drawable.quantum_ic_label_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 188 | case Organization.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 189 | return ResourcesCompat.getDrawable(context.getResources(), |
| 190 | R.drawable.quantum_ic_business_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 191 | case Note.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 192 | return ResourcesCompat.getDrawable(context.getResources(), |
| 193 | R.drawable.quantum_ic_insert_comment_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 194 | case Relation.CONTENT_ITEM_TYPE: |
Marcus Hagerott | 3cbc748 | 2016-12-22 14:37:50 -0800 | [diff] [blame] | 195 | return ResourcesCompat.getDrawable(context.getResources(), |
| 196 | R.drawable.quantum_ic_circles_ext_vd_theme_24, null); |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 197 | default: |
| 198 | return null; |
| 199 | } |
| 200 | } |
Wenyi Wang | 3daa9a3 | 2015-09-25 09:59:06 -0700 | [diff] [blame] | 201 | |
| 202 | /** |
| 203 | * Returns a ringtone string based on the ringtone URI and version #. |
| 204 | */ |
| 205 | public static String getRingtoneStringFromUri(Uri pickedUri, int currentVersion) { |
| 206 | if (isNewerThanM(currentVersion)) { |
| 207 | if (pickedUri == null) return ""; // silent ringtone |
| 208 | if (RingtoneManager.isDefault(pickedUri)) return null; // default ringtone |
| 209 | } |
| 210 | if (pickedUri == null || RingtoneManager.isDefault(pickedUri)) return null; |
| 211 | return pickedUri.toString(); |
| 212 | } |
| 213 | |
| 214 | /** |
| 215 | * Returns a ringtone URI, based on the string and version #. |
| 216 | */ |
| 217 | public static Uri getRingtoneUriFromString(String str, int currentVersion) { |
| 218 | if (str != null) { |
| 219 | if (isNewerThanM(currentVersion) && TextUtils.isEmpty(str)) return null; |
| 220 | return Uri.parse(str); |
| 221 | } |
| 222 | return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); |
| 223 | } |
| 224 | |
| 225 | private static boolean isNewerThanM(int currentVersion) { |
| 226 | return currentVersion > Build.VERSION_CODES.M; |
| 227 | } |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 228 | |
Walter Jang | 3f18d61 | 2015-10-07 16:01:05 -0700 | [diff] [blame] | 229 | /** Returns the {@link Photo#PHOTO_FILE_ID} from the given ValuesDelta. */ |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 230 | public static Long getPhotoFileId(ValuesDelta valuesDelta) { |
| 231 | if (valuesDelta == null) return null; |
Wenyi Wang | 2a4848a | 2016-03-29 01:44:01 +0000 | [diff] [blame] | 232 | if (valuesDelta.getAfter() == null || valuesDelta.getAfter().get(Photo.PHOTO) == null) { |
Walter Jang | 31a74ad | 2015-10-02 19:17:39 -0700 | [diff] [blame] | 233 | return valuesDelta.getAsLong(Photo.PHOTO_FILE_ID); |
| 234 | } |
| 235 | return null; |
| 236 | } |
| 237 | |
| 238 | /** Binds the full resolution image at the given Uri to the provided ImageView. */ |
| 239 | static void loadPhoto(ContactPhotoManager contactPhotoManager, ImageView imageView, |
| 240 | Uri photoUri) { |
| 241 | final DefaultImageProvider fallbackToPreviousImage = new DefaultImageProvider() { |
| 242 | @Override |
| 243 | public void applyDefaultImage(ImageView view, int extent, boolean darkTheme, |
| 244 | DefaultImageRequest defaultImageRequest) { |
| 245 | // Before we finish setting the full sized image, don't change the current |
| 246 | // image that is set in any way. |
| 247 | } |
| 248 | }; |
| 249 | contactPhotoManager.loadPhoto(imageView, photoUri, imageView.getWidth(), |
| 250 | /* darkTheme =*/ false, /* isCircular =*/ false, |
| 251 | /* defaultImageRequest =*/ null, fallbackToPreviousImage); |
| 252 | } |
| 253 | |
| 254 | /** Decodes the Bitmap from the photo bytes from the given ValuesDelta. */ |
| 255 | public static Bitmap getPhotoBitmap(ValuesDelta valuesDelta) { |
| 256 | if (valuesDelta == null) return null; |
| 257 | final byte[] bytes = valuesDelta.getAsByteArray(Photo.PHOTO); |
| 258 | if (bytes == null) return null; |
| 259 | return BitmapFactory.decodeByteArray(bytes, /* offset =*/ 0, bytes.length); |
| 260 | } |
| 261 | |
| 262 | /** Binds the default avatar to the given ImageView and tints it to match QuickContacts. */ |
| 263 | public static void setDefaultPhoto(ImageView imageView , Resources resources, |
| 264 | MaterialPalette materialPalette) { |
| 265 | // Use the default avatar drawable |
| 266 | imageView.setImageDrawable(ContactPhotoManager.getDefaultAvatarDrawableForContact( |
| 267 | resources, /* hires =*/ false, /* defaultImageRequest =*/ null)); |
| 268 | |
| 269 | // Tint it to match the quick contacts |
| 270 | if (imageView instanceof QuickContactImageView) { |
| 271 | ((QuickContactImageView) imageView).setTint(materialPalette == null |
| 272 | ? getDefaultPrimaryAndSecondaryColors(resources).mPrimaryColor |
| 273 | : materialPalette.mPrimaryColor); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | /** Returns compressed bitmap bytes from the given Uri, scaled to the thumbnail dimensions. */ |
| 278 | public static byte[] getCompressedThumbnailBitmapBytes(Context context, Uri uri) |
| 279 | throws FileNotFoundException { |
| 280 | final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(context, uri); |
| 281 | final int size = ContactsUtils.getThumbnailSize(context); |
| 282 | final Bitmap bitmapScaled = Bitmap.createScaledBitmap( |
| 283 | bitmap, size, size, /* filter =*/ false); |
| 284 | return ContactPhotoUtils.compressBitmap(bitmapScaled); |
| 285 | } |
Walter Jang | 7b0970f | 2016-09-01 10:40:19 -0700 | [diff] [blame] | 286 | |
Chiao Cheng | ddd4e82 | 2012-12-06 12:18:01 -0800 | [diff] [blame] | 287 | } |