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