Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.contacts.detail; |
| 18 | |
Brian Attwell | fc50bdd | 2014-02-04 21:14:02 -0800 | [diff] [blame] | 19 | import com.google.common.collect.Iterables; |
| 20 | |
| 21 | import com.android.contacts.R; |
| 22 | import com.android.contacts.common.model.Contact; |
| 23 | import com.android.contacts.common.model.RawContact; |
| 24 | import com.android.contacts.common.model.dataitem.DataItem; |
| 25 | import com.android.contacts.common.model.dataitem.OrganizationDataItem; |
| 26 | import com.android.contacts.common.preference.ContactsPreferences; |
| 27 | import com.android.contacts.util.MoreMath; |
| 28 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 29 | import android.content.Context; |
Flavio Lerda | 65ca8b2 | 2011-08-09 20:46:23 +0100 | [diff] [blame] | 30 | import android.content.pm.PackageManager; |
| 31 | import android.content.pm.PackageManager.NameNotFoundException; |
| 32 | import android.content.res.Resources; |
| 33 | import android.content.res.Resources.NotFoundException; |
Flavio Lerda | 65ca8b2 | 2011-08-09 20:46:23 +0100 | [diff] [blame] | 34 | import android.graphics.drawable.Drawable; |
Dave Santoro | 3915600 | 2011-07-19 01:18:14 -0700 | [diff] [blame] | 35 | import android.net.Uri; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 36 | import android.provider.ContactsContract.DisplayNameSources; |
Brian Attwell | c62cc79 | 2014-10-02 12:35:07 -0700 | [diff] [blame] | 37 | import android.text.BidiFormatter; |
Dave Santoro | 3915600 | 2011-07-19 01:18:14 -0700 | [diff] [blame] | 38 | import android.text.Html; |
Brian Attwell | c62cc79 | 2014-10-02 12:35:07 -0700 | [diff] [blame] | 39 | import android.text.TextDirectionHeuristics; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 40 | import android.text.TextUtils; |
Flavio Lerda | 65ca8b2 | 2011-08-09 20:46:23 +0100 | [diff] [blame] | 41 | import android.util.Log; |
Daniel Lehmann | c42ea4e | 2012-02-16 21:22:37 -0800 | [diff] [blame] | 42 | import android.view.MenuItem; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 43 | import android.view.View; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 44 | import android.widget.ImageView; |
Katherine Kuan | 6c0470e | 2011-08-17 12:33:18 -0700 | [diff] [blame] | 45 | import android.widget.ListView; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 46 | import android.widget.TextView; |
| 47 | |
Dave Santoro | 3915600 | 2011-07-19 01:18:14 -0700 | [diff] [blame] | 48 | import java.util.List; |
| 49 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 50 | /** |
| 51 | * This class contains utility methods to bind high-level contact details |
| 52 | * (meaning name, phonetic name, job, and attribution) from a |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 53 | * {@link Contact} data object to appropriate {@link View}s. |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 54 | */ |
Paul Soulos | 333091a | 2014-07-22 13:54:41 -0700 | [diff] [blame] | 55 | public class ContactDisplayUtils { |
| 56 | private static final String TAG = "ContactDisplayUtils"; |
Brian Attwell | c62cc79 | 2014-10-02 12:35:07 -0700 | [diff] [blame] | 57 | private static BidiFormatter sBidiFormatter = BidiFormatter.getInstance(); |
Flavio Lerda | 65ca8b2 | 2011-08-09 20:46:23 +0100 | [diff] [blame] | 58 | |
Makoto Onuki | f748d59 | 2011-08-18 17:22:39 -0700 | [diff] [blame] | 59 | /** |
Makoto Onuki | 599700f | 2011-08-08 18:43:20 -0700 | [diff] [blame] | 60 | * Returns the display name of the contact, using the current display order setting. |
| 61 | * Returns res/string/missing_name if there is no display name. |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 62 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 63 | public static CharSequence getDisplayName(Context context, Contact contactData) { |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 64 | ContactsPreferences prefs = new ContactsPreferences(context); |
Alon Albert | e09b991 | 2013-09-05 12:58:45 -0700 | [diff] [blame] | 65 | final CharSequence displayName = contactData.getDisplayName(); |
Yorke Lee | c9bb217 | 2014-07-10 11:38:34 -0700 | [diff] [blame] | 66 | if (prefs.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY) { |
Alon Albert | e09b991 | 2013-09-05 12:58:45 -0700 | [diff] [blame] | 67 | if (!TextUtils.isEmpty(displayName)) { |
Brian Attwell | c62cc79 | 2014-10-02 12:35:07 -0700 | [diff] [blame] | 68 | if (contactData.getDisplayNameSource() == DisplayNameSources.PHONE) { |
| 69 | return sBidiFormatter.unicodeWrap( |
| 70 | displayName.toString(), TextDirectionHeuristics.LTR); |
| 71 | } |
Alon Albert | e09b991 | 2013-09-05 12:58:45 -0700 | [diff] [blame] | 72 | return displayName; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 73 | } |
Katherine Kuan | 81281ee | 2011-07-28 16:20:59 -0700 | [diff] [blame] | 74 | } else { |
Alon Albert | e09b991 | 2013-09-05 12:58:45 -0700 | [diff] [blame] | 75 | final CharSequence altDisplayName = contactData.getAltDisplayName(); |
| 76 | if (!TextUtils.isEmpty(altDisplayName)) { |
| 77 | return altDisplayName; |
| 78 | } |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 79 | } |
Alon Albert | e09b991 | 2013-09-05 12:58:45 -0700 | [diff] [blame] | 80 | return context.getResources().getString(R.string.missing_name); |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | /** |
| 84 | * Returns the phonetic name of the contact or null if there isn't one. |
| 85 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 86 | public static String getPhoneticName(Context context, Contact contactData) { |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 87 | String phoneticName = contactData.getPhoneticName(); |
| 88 | if (!TextUtils.isEmpty(phoneticName)) { |
| 89 | return phoneticName; |
| 90 | } |
| 91 | return null; |
| 92 | } |
| 93 | |
| 94 | /** |
Katherine Kuan | afd283a | 2011-08-22 16:55:19 -0700 | [diff] [blame] | 95 | * Returns the attribution string for the contact, which may specify the contact directory that |
| 96 | * the contact came from. Returns null if there is none applicable. |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 97 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 98 | public static String getAttribution(Context context, Contact contactData) { |
Katherine Kuan | afd283a | 2011-08-22 16:55:19 -0700 | [diff] [blame] | 99 | if (contactData.isDirectoryEntry()) { |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 100 | String directoryDisplayName = contactData.getDirectoryDisplayName(); |
| 101 | String directoryType = contactData.getDirectoryType(); |
Yorke Lee | 2e38583 | 2013-09-09 14:42:01 -0700 | [diff] [blame] | 102 | final String displayName; |
| 103 | if (!TextUtils.isEmpty(directoryDisplayName)) { |
| 104 | displayName = directoryDisplayName; |
| 105 | } else if (!TextUtils.isEmpty(directoryType)) { |
| 106 | displayName = directoryType; |
| 107 | } else { |
| 108 | return null; |
| 109 | } |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 110 | return context.getString(R.string.contact_directory_description, displayName); |
| 111 | } |
| 112 | return null; |
| 113 | } |
| 114 | |
| 115 | /** |
| 116 | * Returns the organization of the contact. If several organizations are given, |
| 117 | * the first one is used. Returns null if not applicable. |
| 118 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 119 | public static String getCompany(Context context, Contact contactData) { |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 120 | final boolean displayNameIsOrganization = contactData.getDisplayNameSource() |
| 121 | == DisplayNameSources.ORGANIZATION; |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 122 | for (RawContact rawContact : contactData.getRawContacts()) { |
| 123 | for (DataItem dataItem : Iterables.filter( |
| 124 | rawContact.getDataItems(), OrganizationDataItem.class)) { |
| 125 | OrganizationDataItem organization = (OrganizationDataItem) dataItem; |
| 126 | final String company = organization.getCompany(); |
| 127 | final String title = organization.getTitle(); |
| 128 | final String combined; |
| 129 | // We need to show company and title in a combined string. However, if the |
| 130 | // DisplayName is already the organization, it mirrors company or (if company |
| 131 | // is empty title). Make sure we don't show what's already shown as DisplayName |
| 132 | if (TextUtils.isEmpty(company)) { |
| 133 | combined = displayNameIsOrganization ? null : title; |
| 134 | } else { |
| 135 | if (TextUtils.isEmpty(title)) { |
| 136 | combined = displayNameIsOrganization ? null : company; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 137 | } else { |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 138 | if (displayNameIsOrganization) { |
| 139 | combined = title; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 140 | } else { |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 141 | combined = context.getString( |
| 142 | R.string.organization_company_and_title, |
| 143 | company, title); |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 144 | } |
| 145 | } |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 146 | } |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 147 | |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 148 | if (!TextUtils.isEmpty(combined)) { |
| 149 | return combined; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 150 | } |
| 151 | } |
| 152 | } |
| 153 | return null; |
| 154 | } |
| 155 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 156 | /** |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 157 | * Sets the starred state of this contact. |
| 158 | */ |
Daniel Lehmann | c42ea4e | 2012-02-16 21:22:37 -0800 | [diff] [blame] | 159 | public static void configureStarredImageView(ImageView starredView, boolean isDirectoryEntry, |
| 160 | boolean isUserProfile, boolean isStarred) { |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 161 | // Check if the starred state should be visible |
Daniel Lehmann | c42ea4e | 2012-02-16 21:22:37 -0800 | [diff] [blame] | 162 | if (!isDirectoryEntry && !isUserProfile) { |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 163 | starredView.setVisibility(View.VISIBLE); |
Daniel Lehmann | c42ea4e | 2012-02-16 21:22:37 -0800 | [diff] [blame] | 164 | final int resId = isStarred |
| 165 | ? R.drawable.btn_star_on_normal_holo_light |
| 166 | : R.drawable.btn_star_off_normal_holo_light; |
| 167 | starredView.setImageResource(resId); |
| 168 | starredView.setTag(isStarred); |
| 169 | starredView.setContentDescription(starredView.getResources().getString( |
| 170 | isStarred ? R.string.menu_removeStar : R.string.menu_addStar)); |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 171 | } else { |
| 172 | starredView.setVisibility(View.GONE); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | /** |
Daniel Lehmann | c42ea4e | 2012-02-16 21:22:37 -0800 | [diff] [blame] | 177 | * Sets the starred state of this contact. |
| 178 | */ |
| 179 | public static void configureStarredMenuItem(MenuItem starredMenuItem, boolean isDirectoryEntry, |
| 180 | boolean isUserProfile, boolean isStarred) { |
| 181 | // Check if the starred state should be visible |
| 182 | if (!isDirectoryEntry && !isUserProfile) { |
| 183 | starredMenuItem.setVisible(true); |
| 184 | final int resId = isStarred |
Brian Attwell | d28851f | 2014-06-10 13:25:07 -0700 | [diff] [blame] | 185 | ? R.drawable.ic_star_24dp |
| 186 | : R.drawable.ic_star_outline_24dp; |
Daniel Lehmann | c42ea4e | 2012-02-16 21:22:37 -0800 | [diff] [blame] | 187 | starredMenuItem.setIcon(resId); |
| 188 | starredMenuItem.setChecked(isStarred); |
| 189 | starredMenuItem.setTitle(isStarred ? R.string.menu_removeStar : R.string.menu_addStar); |
| 190 | } else { |
| 191 | starredMenuItem.setVisible(false); |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | /** |
Katherine Kuan | 2eb969c | 2011-06-28 11:43:15 -0700 | [diff] [blame] | 196 | * Sets the display name of this contact to the given {@link TextView}. If |
| 197 | * there is none, then set the view to gone. |
| 198 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 199 | public static void setDisplayName(Context context, Contact contactData, TextView textView) { |
Katherine Kuan | 2eb969c | 2011-06-28 11:43:15 -0700 | [diff] [blame] | 200 | if (textView == null) { |
| 201 | return; |
| 202 | } |
| 203 | setDataOrHideIfNone(getDisplayName(context, contactData), textView); |
| 204 | } |
| 205 | |
| 206 | /** |
| 207 | * Sets the company and job title of this contact to the given {@link TextView}. If |
| 208 | * there is none, then set the view to gone. |
| 209 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 210 | public static void setCompanyName(Context context, Contact contactData, TextView textView) { |
Katherine Kuan | 2eb969c | 2011-06-28 11:43:15 -0700 | [diff] [blame] | 211 | if (textView == null) { |
| 212 | return; |
| 213 | } |
| 214 | setDataOrHideIfNone(getCompany(context, contactData), textView); |
| 215 | } |
| 216 | |
| 217 | /** |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 218 | * Sets the phonetic name of this contact to the given {@link TextView}. If |
| 219 | * there is none, then set the view to gone. |
| 220 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 221 | public static void setPhoneticName(Context context, Contact contactData, TextView textView) { |
Katherine Kuan | 2eb969c | 2011-06-28 11:43:15 -0700 | [diff] [blame] | 222 | if (textView == null) { |
| 223 | return; |
| 224 | } |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 225 | setDataOrHideIfNone(getPhoneticName(context, contactData), textView); |
| 226 | } |
| 227 | |
| 228 | /** |
| 229 | * Sets the attribution contact to the given {@link TextView}. If |
| 230 | * there is none, then set the view to gone. |
| 231 | */ |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 232 | public static void setAttribution(Context context, Contact contactData, TextView textView) { |
Katherine Kuan | 2eb969c | 2011-06-28 11:43:15 -0700 | [diff] [blame] | 233 | if (textView == null) { |
| 234 | return; |
| 235 | } |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame] | 236 | setDataOrHideIfNone(getAttribution(context, contactData), textView); |
| 237 | } |
| 238 | |
| 239 | /** |
| 240 | * Helper function to display the given text in the {@link TextView} or |
| 241 | * hides the {@link TextView} if the text is empty or null. |
| 242 | */ |
| 243 | private static void setDataOrHideIfNone(CharSequence textToDisplay, TextView textView) { |
| 244 | if (!TextUtils.isEmpty(textToDisplay)) { |
| 245 | textView.setText(textToDisplay); |
| 246 | textView.setVisibility(View.VISIBLE); |
| 247 | } else { |
| 248 | textView.setText(null); |
| 249 | textView.setVisibility(View.GONE); |
| 250 | } |
| 251 | } |
| 252 | |
Makoto Onuki | da9cdc1 | 2012-02-27 16:11:50 -0800 | [diff] [blame] | 253 | private static Html.ImageGetter sImageGetter; |
| 254 | |
| 255 | public static Html.ImageGetter getImageGetter(Context context) { |
| 256 | if (sImageGetter == null) { |
| 257 | sImageGetter = new DefaultImageGetter(context.getPackageManager()); |
| 258 | } |
| 259 | return sImageGetter; |
| 260 | } |
| 261 | |
Flavio Lerda | 65ca8b2 | 2011-08-09 20:46:23 +0100 | [diff] [blame] | 262 | /** Fetcher for images from resources to be included in HTML text. */ |
| 263 | private static class DefaultImageGetter implements Html.ImageGetter { |
| 264 | /** The scheme used to load resources. */ |
| 265 | private static final String RES_SCHEME = "res"; |
| 266 | |
| 267 | private final PackageManager mPackageManager; |
| 268 | |
| 269 | public DefaultImageGetter(PackageManager packageManager) { |
| 270 | mPackageManager = packageManager; |
| 271 | } |
| 272 | |
| 273 | @Override |
| 274 | public Drawable getDrawable(String source) { |
| 275 | // Returning null means that a default image will be used. |
| 276 | Uri uri; |
| 277 | try { |
| 278 | uri = Uri.parse(source); |
| 279 | } catch (Throwable e) { |
| 280 | Log.d(TAG, "Could not parse image source: " + source); |
| 281 | return null; |
| 282 | } |
| 283 | if (!RES_SCHEME.equals(uri.getScheme())) { |
| 284 | Log.d(TAG, "Image source does not correspond to a resource: " + source); |
| 285 | return null; |
| 286 | } |
| 287 | // The URI authority represents the package name. |
| 288 | String packageName = uri.getAuthority(); |
| 289 | |
| 290 | Resources resources = getResourcesForResourceName(packageName); |
| 291 | if (resources == null) { |
| 292 | Log.d(TAG, "Could not parse image source: " + source); |
| 293 | return null; |
| 294 | } |
| 295 | |
| 296 | List<String> pathSegments = uri.getPathSegments(); |
| 297 | if (pathSegments.size() != 1) { |
| 298 | Log.d(TAG, "Could not parse image source: " + source); |
| 299 | return null; |
| 300 | } |
| 301 | |
| 302 | final String name = pathSegments.get(0); |
| 303 | final int resId = resources.getIdentifier(name, "drawable", packageName); |
| 304 | |
| 305 | if (resId == 0) { |
| 306 | // Use the default image icon in this case. |
| 307 | Log.d(TAG, "Cannot resolve resource identifier: " + source); |
| 308 | return null; |
| 309 | } |
| 310 | |
| 311 | try { |
| 312 | return getResourceDrawable(resources, resId); |
| 313 | } catch (NotFoundException e) { |
| 314 | Log.d(TAG, "Resource not found: " + source, e); |
| 315 | return null; |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | /** Returns the drawable associated with the given id. */ |
| 320 | private Drawable getResourceDrawable(Resources resources, int resId) |
| 321 | throws NotFoundException { |
| 322 | Drawable drawable = resources.getDrawable(resId); |
| 323 | drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); |
| 324 | return drawable; |
| 325 | } |
| 326 | |
| 327 | /** Returns the {@link Resources} of the package of the given resource name. */ |
| 328 | private Resources getResourcesForResourceName(String packageName) { |
| 329 | try { |
| 330 | return mPackageManager.getResourcesForApplication(packageName); |
| 331 | } catch (NameNotFoundException e) { |
| 332 | Log.d(TAG, "Could not find package: " + packageName); |
| 333 | return null; |
| 334 | } |
| 335 | } |
| 336 | } |
Katherine Kuan | 25594d6 | 2011-08-12 16:05:15 -0700 | [diff] [blame] | 337 | |
| 338 | /** |
| 339 | * Sets an alpha value on the view. |
| 340 | */ |
| 341 | public static void setAlphaOnViewBackground(View view, float alpha) { |
| 342 | if (view != null) { |
| 343 | // Convert alpha layer to a black background HEX color with an alpha value for better |
| 344 | // performance (i.e. use setBackgroundColor() instead of setAlpha()) |
Josh Gargus | 187c816 | 2012-03-13 17:06:53 -0700 | [diff] [blame] | 345 | view.setBackgroundColor((int) (MoreMath.clamp(alpha, 0.0f, 1.0f) * 255) << 24); |
Katherine Kuan | 25594d6 | 2011-08-12 16:05:15 -0700 | [diff] [blame] | 346 | } |
| 347 | } |
Katherine Kuan | 6c0470e | 2011-08-17 12:33:18 -0700 | [diff] [blame] | 348 | |
| 349 | /** |
| 350 | * Returns the top coordinate of the first item in the {@link ListView}. If the first item |
| 351 | * in the {@link ListView} is not visible or there are no children in the list, then return |
| 352 | * Integer.MIN_VALUE. Note that the returned value will be <= 0 because the first item in the |
| 353 | * list cannot have a positive offset. |
| 354 | */ |
| 355 | public static int getFirstListItemOffset(ListView listView) { |
| 356 | if (listView == null || listView.getChildCount() == 0 || |
| 357 | listView.getFirstVisiblePosition() != 0) { |
| 358 | return Integer.MIN_VALUE; |
| 359 | } |
| 360 | return listView.getChildAt(0).getTop(); |
| 361 | } |
| 362 | |
| 363 | /** |
| 364 | * Tries to scroll the first item in the list to the given offset (this can be a no-op if the |
| 365 | * list is already in the correct position). |
| 366 | * @param listView that should be scrolled |
| 367 | * @param offset which should be <= 0 |
| 368 | */ |
| 369 | public static void requestToMoveToOffset(ListView listView, int offset) { |
| 370 | // We try to offset the list if the first item in the list is showing (which is presumed |
| 371 | // to have a larger height than the desired offset). If the first item in the list is not |
| 372 | // visible, then we simply do not scroll the list at all (since it can get complicated to |
| 373 | // compute how many items in the list will equal the given offset). Potentially |
| 374 | // some animation elsewhere will make the transition smoother for the user to compensate |
| 375 | // for this simplification. |
| 376 | if (listView == null || listView.getChildCount() == 0 || |
| 377 | listView.getFirstVisiblePosition() != 0 || offset > 0) { |
| 378 | return; |
| 379 | } |
| 380 | |
| 381 | // As an optimization, check if the first item is already at the given offset. |
| 382 | if (listView.getChildAt(0).getTop() == offset) { |
| 383 | return; |
| 384 | } |
| 385 | |
| 386 | listView.setSelectionFromTop(0, offset); |
| 387 | } |
Flavio Lerda | 22cb663 | 2011-08-03 22:59:58 +0100 | [diff] [blame] | 388 | } |