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