Home | History | Annotate | Download | only in editor
      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 
     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 
     24 import android.content.Context;
     25 import android.content.res.Resources;
     26 import android.graphics.Bitmap;
     27 import android.graphics.BitmapFactory;
     28 import android.graphics.drawable.Drawable;
     29 import android.media.RingtoneManager;
     30 import android.net.Uri;
     31 import android.os.Build;
     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;
     43 import android.support.v4.content.res.ResourcesCompat;
     44 import android.text.TextUtils;
     45 import android.widget.ImageView;
     46 
     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;
     51 import com.android.contacts.R;
     52 import com.android.contacts.model.ValuesDelta;
     53 import com.android.contacts.model.account.AccountDisplayInfo;
     54 import com.android.contacts.model.account.AccountInfo;
     55 import com.android.contacts.model.dataitem.DataKind;
     56 import com.android.contacts.util.ContactPhotoUtils;
     57 import com.android.contacts.util.MaterialColorMapUtils.MaterialPalette;
     58 import com.android.contacts.widget.QuickContactImageView;
     59 
     60 import com.google.common.collect.Maps;
     61 
     62 import java.io.FileNotFoundException;
     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.
     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     }
    111 
    112 
    113     public static String getAccountHeaderLabelForMyProfile(Context context,
    114             AccountInfo accountInfo) {
    115         if (accountInfo.isDeviceAccount()) {
    116             return context.getString(R.string.local_profile_title);
    117         } else {
    118             return context.getString(R.string.external_profile_title,
    119                     accountInfo.getTypeLabel());
    120         }
    121     }
    122 
    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());
    131         } else {
    132             return context.getString(R.string.account_type_format,
    133                     displayableAccount.getTypeLabel());
    134         }
    135     }
    136 
    137     /**
    138      * Returns a content description String for the container of the account information
    139      * returned by {@link #getAccountTypeHeaderLabel(Context, AccountDisplayInfo)}.
    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)) {
    148             builder.append(accountName);
    149         }
    150         return builder.toString();
    151     }
    152 
    153     /**
    154      * Return an icon that represents {@param mimeType}.
    155      */
    156     public static Drawable getMimeTypeDrawable(Context context, String mimeType) {
    157         switch (mimeType) {
    158             case StructuredName.CONTENT_ITEM_TYPE:
    159                 return ResourcesCompat.getDrawable(context.getResources(),
    160                         R.drawable.quantum_ic_person_vd_theme_24, null);
    161             case StructuredPostal.CONTENT_ITEM_TYPE:
    162                 return ResourcesCompat.getDrawable(context.getResources(),
    163                         R.drawable.quantum_ic_place_vd_theme_24, null);
    164             case SipAddress.CONTENT_ITEM_TYPE:
    165                 return ResourcesCompat.getDrawable(context.getResources(),
    166                         R.drawable.quantum_ic_dialer_sip_vd_theme_24, null);
    167             case Phone.CONTENT_ITEM_TYPE:
    168                 return ResourcesCompat.getDrawable(context.getResources(),
    169                         R.drawable.quantum_ic_phone_vd_theme_24, null);
    170             case Im.CONTENT_ITEM_TYPE:
    171                 return ResourcesCompat.getDrawable(context.getResources(),
    172                         R.drawable.quantum_ic_message_vd_theme_24, null);
    173             case Event.CONTENT_ITEM_TYPE:
    174                 return ResourcesCompat.getDrawable(context.getResources(),
    175                         R.drawable.quantum_ic_event_vd_theme_24, null);
    176             case Email.CONTENT_ITEM_TYPE:
    177                 return ResourcesCompat.getDrawable(context.getResources(),
    178                         R.drawable.quantum_ic_email_vd_theme_24, null);
    179             case Website.CONTENT_ITEM_TYPE:
    180                 return ResourcesCompat.getDrawable(context.getResources(),
    181                         R.drawable.quantum_ic_public_vd_theme_24, null);
    182             case Photo.CONTENT_ITEM_TYPE:
    183                 return ResourcesCompat.getDrawable(context.getResources(),
    184                         R.drawable.quantum_ic_camera_alt_vd_theme_24, null);
    185             case GroupMembership.CONTENT_ITEM_TYPE:
    186                 return ResourcesCompat.getDrawable(context.getResources(),
    187                         R.drawable.quantum_ic_label_vd_theme_24, null);
    188             case Organization.CONTENT_ITEM_TYPE:
    189                 return ResourcesCompat.getDrawable(context.getResources(),
    190                         R.drawable.quantum_ic_business_vd_theme_24, null);
    191             case Note.CONTENT_ITEM_TYPE:
    192                 return ResourcesCompat.getDrawable(context.getResources(),
    193                         R.drawable.quantum_ic_insert_comment_vd_theme_24, null);
    194             case Relation.CONTENT_ITEM_TYPE:
    195                 return ResourcesCompat.getDrawable(context.getResources(),
    196                         R.drawable.quantum_ic_circles_ext_vd_theme_24, null);
    197             default:
    198                 return null;
    199         }
    200     }
    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     }
    228 
    229     /** Returns the {@link Photo#PHOTO_FILE_ID} from the given ValuesDelta. */
    230     public static Long getPhotoFileId(ValuesDelta valuesDelta) {
    231         if (valuesDelta == null) return null;
    232         if (valuesDelta.getAfter() == null || valuesDelta.getAfter().get(Photo.PHOTO) == null) {
    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     }
    286 
    287 }
    288