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