Loading AndroidManifest.xml +2 −3 Original line number Diff line number Diff line Loading @@ -16,8 +16,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.contacts" android:sharedUserId="android.uid.shared" > android:sharedUserId="android.uid.shared"> <uses-permission android:name="android.permission.CALL_PRIVILEGED" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> Loading res/layout-finger/recent_calls_list_item.xml +25 −4 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:paddingLeft="7dip" android:paddingLeft="4dip" > <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon" Loading @@ -38,7 +38,7 @@ android:layout_marginTop="5dip" android:layout_marginBottom="5dip" android:layout_toLeftOf="@id/call_icon" android:layout_marginLeft="11dip" android:layout_marginLeft="2dip" android:background="@drawable/divider_vertical_dark" /> Loading @@ -47,6 +47,9 @@ android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toLeftOf="@id/divider" android:layout_alignWithParentIfMissing="true" android:layout_marginRight="9dip" android:layout_marginLeft="3dip" /> <TextView android:id="@+id/date" Loading @@ -55,6 +58,8 @@ android:layout_toLeftOf="@id/divider" android:layout_alignParentBottom="true" android:layout_marginBottom="8dip" android:layout_alignWithParentIfMissing="true" android:layout_marginRight="5dip" android:textAppearance="?android:attr/textAppearanceSmall" android:singleLine="true" Loading @@ -63,10 +68,12 @@ <TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_toRightOf="@id/photo" android:layout_alignParentBottom="true" android:layout_marginBottom="8dip" android:layout_marginTop="-10dip" android:layout_marginLeft="8dip" android:layout_alignWithParentIfMissing="true" android:singleLine="true" android:ellipsize="marquee" Loading @@ -88,13 +95,27 @@ android:textAppearance="?android:attr/textAppearanceSmall" /> <android.widget.QuickContactBadge android:id="@+id/photo" android:layout_alignParentLeft="true" android:layout_centerVertical="true" style="@*android:style/Widget.QuickContactBadge.WindowLarge" /> /> <ImageView android:id="@+id/noQuickContactPhoto" android:layout_alignParentLeft="true" android:layout_centerVertical="true" style="@*android:style/Widget.QuickContactBadge.WindowMedium" android:background="@null" /> /> <TextView android:id="@+id/line1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_toRightOf="@id/photo" android:layout_toLeftOf="@+id/call_type_icon" android:layout_above="@id/label" android:layout_marginLeft="8dip" android:layout_alignWithParentIfMissing="true" android:textAppearance="?android:attr/textAppearanceLarge" Loading res/values/strings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -1303,7 +1303,7 @@ <string name="title_about_name">Mod Name</string> <string name="summary_about_name">WyContacts Eclair</string> <string name="title_about_version">Version</string> <string name="summary_about_version">0.9</string> <string name="summary_about_version">1.0</string> <string name="title_about_credits">Credits</string> <string name="summary_about_credits">ChainsDD, geesun, niuchl, rac2030 and the rest of XDA! :)</string> Loading res/xml/contacts_preferences.xml +4 −6 Original line number Diff line number Diff line Loading @@ -56,21 +56,21 @@ android:dialogTitle="@string/title_choose_color" android:entries="@array/digits_colors" android:entryValues="@array/digits_colors_values" android:defaultValue="-1" /> android:defaultValue="-16777216" /> <ListPreference android:key="focused_digit_color" android:title="@string/title_digits_color_focused" android:dialogTitle="@string/title_choose_color" android:entries="@array/digits_colors" android:entryValues="@array/digits_colors_values" android:defaultValue="-16777216" /> android:defaultValue="-1" /> <ListPreference android:key="unselected_digit_color" android:title="@string/title_digits_color_unselected" android:dialogTitle="@string/title_choose_color" android:entries="@array/digits_colors" android:entryValues="@array/digits_colors_values" android:defaultValue="-16777216" /> android:defaultValue="-1" /> <CheckBoxPreference android:key="dial_digit_use_custom_color" android:title="@string/title_use_custom_color" Loading @@ -92,17 +92,15 @@ </PreferenceScreen> </PreferenceCategory> <PreferenceCategory android:title="@string/recentCallsIconLabel"> <!-- <CheckBoxPreference android:key="cl_show_dial_button" android:title="@string/title_contacts_show_dial_button" android:summary="@string/summary_contacts_show_dial_button" android:defaultValue="true" /> android:defaultValue="false" /> <CheckBoxPreference android:key="cl_show_pic" android:title="@string/title_contacts_show_pic" android:defaultValue="true" /> --> <CheckBoxPreference android:key="cl_exact_time" android:title="@string/title_cl_exact_time" Loading src/com/android/contacts/RecentCallsListActivity.java +366 −23 Original line number Diff line number Diff line Loading @@ -79,6 +79,19 @@ import android.database.sqlite.SQLiteException; import android.preference.PreferenceManager; import android.text.format.DateFormat; //Wysie: Contact pictures import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.provider.ContactsContract.QuickContact; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.QuickContactBadge; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.lang.ref.SoftReference; import java.util.HashSet; /** * Displays a list of call log entries. */ Loading Loading @@ -113,7 +126,10 @@ public class RecentCallsListActivity extends ListActivity PhoneLookup.DISPLAY_NAME, PhoneLookup.TYPE, PhoneLookup.LABEL, PhoneLookup.NUMBER PhoneLookup.NUMBER, //Wysie: Contact pictures PhoneLookup.PHOTO_ID, PhoneLookup.LOOKUP_KEY }; static final int PERSON_ID_COLUMN_INDEX = 0; Loading @@ -121,6 +137,9 @@ public class RecentCallsListActivity extends ListActivity static final int PHONE_TYPE_COLUMN_INDEX = 2; static final int LABEL_COLUMN_INDEX = 3; static final int MATCHED_NUMBER_COLUMN_INDEX = 4; //Wysie: Contact pictures static final int PHOTO_ID_COLUMN_INDEX = 5; static final int LOOKUP_KEY_COLUMN_INDEX = 6; private static final int MENU_ITEM_DELETE = 1; private static final int MENU_ITEM_DELETE_ALL = 2; Loading Loading @@ -149,6 +168,13 @@ public class RecentCallsListActivity extends ListActivity private static final int MENU_PREFERENCES = 7; //Wysie: Contact pictures private static ExecutorService sImageFetchThreadPool; private int mScrollState; private static boolean mDisplayPhotos; private static boolean isQuickContact; private static boolean showDialButton; static final class ContactInfo { public long personId; public String name; Loading @@ -156,17 +182,26 @@ public class RecentCallsListActivity extends ListActivity public String label; public String number; public String formattedNumber; //Wysie: Contact pictures public long photoId; public String lookupKey; public static ContactInfo EMPTY = new ContactInfo(); } public static final class RecentCallsListItemViews { //Wysie: Contact pictures QuickContactBadge photoView; ImageView nonQuickContactPhotoView; TextView line1View; TextView labelView; TextView numberView; TextView dateView; ImageView iconView; View callView; View dividerView; } static final class CallerInfoQuery { Loading Loading @@ -194,9 +229,24 @@ public class RecentCallsListActivity extends ListActivity */ private static int sFormattingType = FORMATTING_TYPE_INVALID; //Wysie: Contact pictures final static class PhotoInfo { public int position; public long photoId; public Uri contactUri; public PhotoInfo(int position, long photoId, Uri contactUri) { this.position = position; this.photoId = photoId; this.contactUri = contactUri; } public QuickContactBadge photoView; } /** Adapter class to fill in data for the Call Log */ final class RecentCallsAdapter extends ResourceCursorAdapter implements Runnable, ViewTreeObserver.OnPreDrawListener, View.OnClickListener { implements Runnable, ViewTreeObserver.OnPreDrawListener, View.OnClickListener, OnScrollListener { HashMap<String,ContactInfo> mContactInfo; private final LinkedList<CallerInfoQuery> mRequests; private volatile boolean mDone; Loading @@ -213,13 +263,30 @@ public class RecentCallsListActivity extends ListActivity private Drawable mDrawableOutgoing; private Drawable mDrawableMissed; //Wysie private ImageFetchHandler mImageHandler; private ImageDbFetcher mImageFetcher; private static final int FETCH_IMAGE_MSG = 3; //Wysie: Contact pictures private HashMap<Long, SoftReference<Bitmap>> mBitmapCache = null; private HashSet<ImageView> mItemsMissingImages = null; public void onClick(View view) { if (view instanceof QuickContactBadge) { PhotoInfo info = (PhotoInfo)view.getTag(); QuickContact.showQuickContact(mContext, view, info.contactUri, QuickContact.MODE_MEDIUM, null); isQuickContact = true; } else { String number = (String) view.getTag(); if (!TextUtils.isEmpty(number)) { Uri telUri = Uri.fromParts("tel", number, null); startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, telUri)); } } } public boolean onPreDraw() { if (mFirst) { Loading Loading @@ -257,6 +324,11 @@ public class RecentCallsListActivity extends ListActivity mDrawableMissed = getResources().getDrawable( R.drawable.ic_call_log_list_missed_call); mLabelArray = getResources().getTextArray(com.android.internal.R.array.phoneTypes); //Wysie: Contact pictures mBitmapCache = new HashMap<Long, SoftReference<Bitmap>>(); mItemsMissingImages = new HashSet<ImageView>(); mImageHandler = new ImageFetchHandler(); } /** Loading Loading @@ -367,6 +439,10 @@ public class RecentCallsListActivity extends ListActivity info.label = phonesCursor.getString(LABEL_COLUMN_INDEX); info.number = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX); //Wysie: Contact pictures info.photoId = phonesCursor.getLong(PHOTO_ID_COLUMN_INDEX); info.lookupKey = phonesCursor.getString(LOOKUP_KEY_COLUMN_INDEX); // New incoming phone number invalidates our formatted // cache. Any cache fills happen only on the GUI thread. info.formattedNumber = null; Loading Loading @@ -422,9 +498,16 @@ public class RecentCallsListActivity extends ListActivity views.numberView = (TextView) view.findViewById(R.id.number); views.dateView = (TextView) view.findViewById(R.id.date); views.iconView = (ImageView) view.findViewById(R.id.call_type_icon); views.dividerView = view.findViewById(R.id.divider); views.callView = view.findViewById(R.id.call_icon); views.callView.setOnClickListener(this); //Wysie: Contact pictures views.photoView = (QuickContactBadge) view.findViewById(R.id.photo); views.photoView.setOnClickListener(this); views.nonQuickContactPhotoView = (ImageView) view.findViewById(R.id.noQuickContactPhoto); view.setTag(views); return view; Loading @@ -441,9 +524,23 @@ public class RecentCallsListActivity extends ListActivity int callerNumberType = c.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String callerNumberLabel = c.getString(CALLER_NUMBERLABEL_COLUMN_INDEX); //Wysie boolean noContactInfo = false; // Store away the number so we can call it directly if you click on the call icon views.callView.setTag(number); //Wysie: Use iconView to dial out if dial button is hidden if (!showDialButton) { views.iconView.setTag(number); views.iconView.setOnClickListener(this); //views.iconView.setBackgroundResource(R.drawable.call_background); } else { views.iconView.setTag(null); views.iconView.setOnClickListener(null); //views.iconView.setBackgroundResource(0); } // Lookup contacts with this number ContactInfo info = mContactInfo.get(number); if (info == null) { Loading Loading @@ -491,6 +588,7 @@ public class RecentCallsListActivity extends ListActivity // time. For private and unknown numbers: hide it. views.callView.setVisibility(View.VISIBLE); if (!TextUtils.isEmpty(name)) { views.line1View.setText(name); views.labelView.setVisibility(View.VISIBLE); Loading Loading @@ -520,11 +618,77 @@ public class RecentCallsListActivity extends ListActivity number = formatPhoneNumber(number); } //Wysie noContactInfo = true; views.line1View.setText(number); views.numberView.setVisibility(View.GONE); views.labelView.setVisibility(View.GONE); } //Wysie: Contact pictures if (mDisplayPhotos) { long photoId = info.photoId; // Build soft lookup reference final long contactId = info.personId; final String lookupKey = info.lookupKey; Uri contactUri = Contacts.getLookupUri(contactId, lookupKey); ImageView viewToUse; if (noContactInfo) { viewToUse = views.nonQuickContactPhotoView; views.photoView.setVisibility(View.INVISIBLE); views.nonQuickContactPhotoView.setVisibility(View.VISIBLE); } else { viewToUse = views.photoView; //views.photoView.assignContactUri(contactUri); //Wysie: Commented out, we handle it explicityly in onClick() views.photoView.setTag(contactUri); views.photoView.setVisibility(View.VISIBLE); views.nonQuickContactPhotoView.setVisibility(View.INVISIBLE); } final int position = c.getPosition(); viewToUse.setTag(new PhotoInfo(position, photoId, contactUri)); if (photoId == 0) { viewToUse.setImageResource(R.drawable.ic_contact_list_picture); } else { Bitmap photo = null; // Look for the cached bitmap SoftReference<Bitmap> ref = mBitmapCache.get(photoId); if (ref != null) { photo = ref.get(); if (photo == null) { mBitmapCache.remove(photoId); } } // Bind the photo, or use the fallback no photo resource if (photo != null) { viewToUse.setImageBitmap(photo); } else { // Cache miss viewToUse.setImageResource(R.drawable.ic_contact_list_picture); // Add it to a set of images that are populated asynchronously. mItemsMissingImages.add(viewToUse); if (mScrollState != OnScrollListener.SCROLL_STATE_FLING) { // Scrolling is idle or slow, go get the image right now. sendFetchImageMessage(viewToUse); } } } } else { views.photoView.setVisibility(View.GONE); views.nonQuickContactPhotoView.setVisibility(View.GONE); } int type = c.getInt(CALL_TYPE_COLUMN_INDEX); long date = c.getLong(DATE_COLUMN_INDEX); Loading Loading @@ -556,6 +720,14 @@ public class RecentCallsListActivity extends ListActivity views.dateView.setText(DateFormat.format(format, date)); } if (showDialButton) { views.dividerView.setVisibility(View.VISIBLE); views.callView.setVisibility(View.VISIBLE); } else { views.dividerView.setVisibility(View.GONE); views.callView.setVisibility(View.GONE); } // Set the icon switch (type) { case Calls.INCOMING_TYPE: Loading @@ -578,6 +750,161 @@ public class RecentCallsListActivity extends ListActivity view.getViewTreeObserver().addOnPreDrawListener(this); } } //Wysie: Contact pictures private class ImageFetchHandler extends Handler { @Override public void handleMessage(Message message) { if (RecentCallsListActivity.this.isFinishing()) { return; } switch(message.what) { case FETCH_IMAGE_MSG: { final ImageView imageView = (ImageView) message.obj; if (imageView == null) { break; } final PhotoInfo info = (PhotoInfo)imageView.getTag(); if (info == null) { break; } final long photoId = info.photoId; if (photoId == 0) { break; } SoftReference<Bitmap> photoRef = mBitmapCache.get(photoId); if (photoRef == null) { break; } Bitmap photo = photoRef.get(); if (photo == null) { mBitmapCache.remove(photoId); break; } // Make sure the photoId on this image view has not changed // while we were loading the image. synchronized (imageView) { final PhotoInfo updatedInfo = (PhotoInfo)imageView.getTag(); long currentPhotoId = updatedInfo.photoId; if (currentPhotoId == photoId) { imageView.setImageBitmap(photo); mItemsMissingImages.remove(imageView); } } break; } } } public void clearImageFecthing() { removeMessages(FETCH_IMAGE_MSG); } } //Wysie: Contact pictures private class ImageDbFetcher implements Runnable { long mPhotoId; private ImageView mImageView; public ImageDbFetcher(long photoId, ImageView imageView) { this.mPhotoId = photoId; this.mImageView = imageView; } public void run() { if (RecentCallsListActivity.this.isFinishing()) { return; } if (Thread.interrupted()) { // shutdown has been called. return; } Bitmap photo = null; try { photo = ContactsUtils.loadContactPhoto(mContext, mPhotoId, null); } catch (OutOfMemoryError e) { // Not enough memory for the photo, do nothing. } if (photo == null) { return; } mBitmapCache.put(mPhotoId, new SoftReference<Bitmap>(photo)); if (Thread.interrupted()) { // shutdown has been called. return; } // Update must happen on UI thread Message msg = new Message(); msg.what = FETCH_IMAGE_MSG; msg.obj = mImageView; mImageHandler.sendMessage(msg); } } //Wysie: Contact pictures public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // no op } public void onScrollStateChanged(AbsListView view, int scrollState) { mScrollState = scrollState; if (scrollState == OnScrollListener.SCROLL_STATE_FLING) { // If we are in a fling, stop loading images. clearImageFetching(); } else if (mDisplayPhotos) { processMissingImageItems(view); } } private void processMissingImageItems(AbsListView view) { for (ImageView iv : mItemsMissingImages) { sendFetchImageMessage(iv); } } private void sendFetchImageMessage(ImageView view) { final PhotoInfo info = (PhotoInfo) view.getTag(); if (info == null) { return; } final long photoId = info.photoId; if (photoId == 0) { return; } mImageFetcher = new ImageDbFetcher(photoId, view); synchronized (RecentCallsListActivity.this) { // can't sync on sImageFetchThreadPool. if (sImageFetchThreadPool == null) { // Don't use more than 3 threads at a time to update. The thread pool will be // shared by all contact items. sImageFetchThreadPool = Executors.newFixedThreadPool(3); } sImageFetchThreadPool.execute(mImageFetcher); } } public void clearImageFetching() { synchronized (RecentCallsListActivity.this) { if (sImageFetchThreadPool != null) { sImageFetchThreadPool.shutdownNow(); sImageFetchThreadPool = null; } } mImageHandler.clearImageFecthing(); } } private static final class QueryHandler extends AsyncQueryHandler { Loading Loading @@ -638,6 +965,7 @@ public class RecentCallsListActivity extends ListActivity //Wysie ePrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); isQuickContact = false; setContentView(R.layout.recent_calls); Loading @@ -658,23 +986,38 @@ public class RecentCallsListActivity extends ListActivity @Override protected void onResume() { if (isQuickContact) { isQuickContact = false; super.onResume(); } else { // The adapter caches looked up numbers, clear it so they will get // looked up again. if (mAdapter != null) { mAdapter.clearCache(); } // Force cache to reload so we don't show stale photos. if (mAdapter.mBitmapCache != null) { mAdapter.mBitmapCache.clear(); } exactTime = ePrefs.getBoolean("cl_exact_time", true); is24hour = DateFormat.is24HourFormat(this); showSeconds = ePrefs.getBoolean("cl_show_seconds", true); mDisplayPhotos = ePrefs.getBoolean("cl_show_pic", true); showDialButton = ePrefs.getBoolean("cl_show_dial_button", false); super.onResume(); startQuery(); resetNewCallsFlag(); super.onResume(); mScrollState = OnScrollListener.SCROLL_STATE_IDLE; mAdapter.mPreDrawListener = null; // Let it restart the thread after next draw } } @Override protected void onPause() { Loading Loading
AndroidManifest.xml +2 −3 Original line number Diff line number Diff line Loading @@ -16,8 +16,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.contacts" android:sharedUserId="android.uid.shared" > android:sharedUserId="android.uid.shared"> <uses-permission android:name="android.permission.CALL_PRIVILEGED" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> Loading
res/layout-finger/recent_calls_list_item.xml +25 −4 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:paddingLeft="7dip" android:paddingLeft="4dip" > <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon" Loading @@ -38,7 +38,7 @@ android:layout_marginTop="5dip" android:layout_marginBottom="5dip" android:layout_toLeftOf="@id/call_icon" android:layout_marginLeft="11dip" android:layout_marginLeft="2dip" android:background="@drawable/divider_vertical_dark" /> Loading @@ -47,6 +47,9 @@ android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toLeftOf="@id/divider" android:layout_alignWithParentIfMissing="true" android:layout_marginRight="9dip" android:layout_marginLeft="3dip" /> <TextView android:id="@+id/date" Loading @@ -55,6 +58,8 @@ android:layout_toLeftOf="@id/divider" android:layout_alignParentBottom="true" android:layout_marginBottom="8dip" android:layout_alignWithParentIfMissing="true" android:layout_marginRight="5dip" android:textAppearance="?android:attr/textAppearanceSmall" android:singleLine="true" Loading @@ -63,10 +68,12 @@ <TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_toRightOf="@id/photo" android:layout_alignParentBottom="true" android:layout_marginBottom="8dip" android:layout_marginTop="-10dip" android:layout_marginLeft="8dip" android:layout_alignWithParentIfMissing="true" android:singleLine="true" android:ellipsize="marquee" Loading @@ -88,13 +95,27 @@ android:textAppearance="?android:attr/textAppearanceSmall" /> <android.widget.QuickContactBadge android:id="@+id/photo" android:layout_alignParentLeft="true" android:layout_centerVertical="true" style="@*android:style/Widget.QuickContactBadge.WindowLarge" /> /> <ImageView android:id="@+id/noQuickContactPhoto" android:layout_alignParentLeft="true" android:layout_centerVertical="true" style="@*android:style/Widget.QuickContactBadge.WindowMedium" android:background="@null" /> /> <TextView android:id="@+id/line1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_toRightOf="@id/photo" android:layout_toLeftOf="@+id/call_type_icon" android:layout_above="@id/label" android:layout_marginLeft="8dip" android:layout_alignWithParentIfMissing="true" android:textAppearance="?android:attr/textAppearanceLarge" Loading
res/values/strings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -1303,7 +1303,7 @@ <string name="title_about_name">Mod Name</string> <string name="summary_about_name">WyContacts Eclair</string> <string name="title_about_version">Version</string> <string name="summary_about_version">0.9</string> <string name="summary_about_version">1.0</string> <string name="title_about_credits">Credits</string> <string name="summary_about_credits">ChainsDD, geesun, niuchl, rac2030 and the rest of XDA! :)</string> Loading
res/xml/contacts_preferences.xml +4 −6 Original line number Diff line number Diff line Loading @@ -56,21 +56,21 @@ android:dialogTitle="@string/title_choose_color" android:entries="@array/digits_colors" android:entryValues="@array/digits_colors_values" android:defaultValue="-1" /> android:defaultValue="-16777216" /> <ListPreference android:key="focused_digit_color" android:title="@string/title_digits_color_focused" android:dialogTitle="@string/title_choose_color" android:entries="@array/digits_colors" android:entryValues="@array/digits_colors_values" android:defaultValue="-16777216" /> android:defaultValue="-1" /> <ListPreference android:key="unselected_digit_color" android:title="@string/title_digits_color_unselected" android:dialogTitle="@string/title_choose_color" android:entries="@array/digits_colors" android:entryValues="@array/digits_colors_values" android:defaultValue="-16777216" /> android:defaultValue="-1" /> <CheckBoxPreference android:key="dial_digit_use_custom_color" android:title="@string/title_use_custom_color" Loading @@ -92,17 +92,15 @@ </PreferenceScreen> </PreferenceCategory> <PreferenceCategory android:title="@string/recentCallsIconLabel"> <!-- <CheckBoxPreference android:key="cl_show_dial_button" android:title="@string/title_contacts_show_dial_button" android:summary="@string/summary_contacts_show_dial_button" android:defaultValue="true" /> android:defaultValue="false" /> <CheckBoxPreference android:key="cl_show_pic" android:title="@string/title_contacts_show_pic" android:defaultValue="true" /> --> <CheckBoxPreference android:key="cl_exact_time" android:title="@string/title_cl_exact_time" Loading
src/com/android/contacts/RecentCallsListActivity.java +366 −23 Original line number Diff line number Diff line Loading @@ -79,6 +79,19 @@ import android.database.sqlite.SQLiteException; import android.preference.PreferenceManager; import android.text.format.DateFormat; //Wysie: Contact pictures import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.provider.ContactsContract.QuickContact; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.QuickContactBadge; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.lang.ref.SoftReference; import java.util.HashSet; /** * Displays a list of call log entries. */ Loading Loading @@ -113,7 +126,10 @@ public class RecentCallsListActivity extends ListActivity PhoneLookup.DISPLAY_NAME, PhoneLookup.TYPE, PhoneLookup.LABEL, PhoneLookup.NUMBER PhoneLookup.NUMBER, //Wysie: Contact pictures PhoneLookup.PHOTO_ID, PhoneLookup.LOOKUP_KEY }; static final int PERSON_ID_COLUMN_INDEX = 0; Loading @@ -121,6 +137,9 @@ public class RecentCallsListActivity extends ListActivity static final int PHONE_TYPE_COLUMN_INDEX = 2; static final int LABEL_COLUMN_INDEX = 3; static final int MATCHED_NUMBER_COLUMN_INDEX = 4; //Wysie: Contact pictures static final int PHOTO_ID_COLUMN_INDEX = 5; static final int LOOKUP_KEY_COLUMN_INDEX = 6; private static final int MENU_ITEM_DELETE = 1; private static final int MENU_ITEM_DELETE_ALL = 2; Loading Loading @@ -149,6 +168,13 @@ public class RecentCallsListActivity extends ListActivity private static final int MENU_PREFERENCES = 7; //Wysie: Contact pictures private static ExecutorService sImageFetchThreadPool; private int mScrollState; private static boolean mDisplayPhotos; private static boolean isQuickContact; private static boolean showDialButton; static final class ContactInfo { public long personId; public String name; Loading @@ -156,17 +182,26 @@ public class RecentCallsListActivity extends ListActivity public String label; public String number; public String formattedNumber; //Wysie: Contact pictures public long photoId; public String lookupKey; public static ContactInfo EMPTY = new ContactInfo(); } public static final class RecentCallsListItemViews { //Wysie: Contact pictures QuickContactBadge photoView; ImageView nonQuickContactPhotoView; TextView line1View; TextView labelView; TextView numberView; TextView dateView; ImageView iconView; View callView; View dividerView; } static final class CallerInfoQuery { Loading Loading @@ -194,9 +229,24 @@ public class RecentCallsListActivity extends ListActivity */ private static int sFormattingType = FORMATTING_TYPE_INVALID; //Wysie: Contact pictures final static class PhotoInfo { public int position; public long photoId; public Uri contactUri; public PhotoInfo(int position, long photoId, Uri contactUri) { this.position = position; this.photoId = photoId; this.contactUri = contactUri; } public QuickContactBadge photoView; } /** Adapter class to fill in data for the Call Log */ final class RecentCallsAdapter extends ResourceCursorAdapter implements Runnable, ViewTreeObserver.OnPreDrawListener, View.OnClickListener { implements Runnable, ViewTreeObserver.OnPreDrawListener, View.OnClickListener, OnScrollListener { HashMap<String,ContactInfo> mContactInfo; private final LinkedList<CallerInfoQuery> mRequests; private volatile boolean mDone; Loading @@ -213,13 +263,30 @@ public class RecentCallsListActivity extends ListActivity private Drawable mDrawableOutgoing; private Drawable mDrawableMissed; //Wysie private ImageFetchHandler mImageHandler; private ImageDbFetcher mImageFetcher; private static final int FETCH_IMAGE_MSG = 3; //Wysie: Contact pictures private HashMap<Long, SoftReference<Bitmap>> mBitmapCache = null; private HashSet<ImageView> mItemsMissingImages = null; public void onClick(View view) { if (view instanceof QuickContactBadge) { PhotoInfo info = (PhotoInfo)view.getTag(); QuickContact.showQuickContact(mContext, view, info.contactUri, QuickContact.MODE_MEDIUM, null); isQuickContact = true; } else { String number = (String) view.getTag(); if (!TextUtils.isEmpty(number)) { Uri telUri = Uri.fromParts("tel", number, null); startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, telUri)); } } } public boolean onPreDraw() { if (mFirst) { Loading Loading @@ -257,6 +324,11 @@ public class RecentCallsListActivity extends ListActivity mDrawableMissed = getResources().getDrawable( R.drawable.ic_call_log_list_missed_call); mLabelArray = getResources().getTextArray(com.android.internal.R.array.phoneTypes); //Wysie: Contact pictures mBitmapCache = new HashMap<Long, SoftReference<Bitmap>>(); mItemsMissingImages = new HashSet<ImageView>(); mImageHandler = new ImageFetchHandler(); } /** Loading Loading @@ -367,6 +439,10 @@ public class RecentCallsListActivity extends ListActivity info.label = phonesCursor.getString(LABEL_COLUMN_INDEX); info.number = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX); //Wysie: Contact pictures info.photoId = phonesCursor.getLong(PHOTO_ID_COLUMN_INDEX); info.lookupKey = phonesCursor.getString(LOOKUP_KEY_COLUMN_INDEX); // New incoming phone number invalidates our formatted // cache. Any cache fills happen only on the GUI thread. info.formattedNumber = null; Loading Loading @@ -422,9 +498,16 @@ public class RecentCallsListActivity extends ListActivity views.numberView = (TextView) view.findViewById(R.id.number); views.dateView = (TextView) view.findViewById(R.id.date); views.iconView = (ImageView) view.findViewById(R.id.call_type_icon); views.dividerView = view.findViewById(R.id.divider); views.callView = view.findViewById(R.id.call_icon); views.callView.setOnClickListener(this); //Wysie: Contact pictures views.photoView = (QuickContactBadge) view.findViewById(R.id.photo); views.photoView.setOnClickListener(this); views.nonQuickContactPhotoView = (ImageView) view.findViewById(R.id.noQuickContactPhoto); view.setTag(views); return view; Loading @@ -441,9 +524,23 @@ public class RecentCallsListActivity extends ListActivity int callerNumberType = c.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String callerNumberLabel = c.getString(CALLER_NUMBERLABEL_COLUMN_INDEX); //Wysie boolean noContactInfo = false; // Store away the number so we can call it directly if you click on the call icon views.callView.setTag(number); //Wysie: Use iconView to dial out if dial button is hidden if (!showDialButton) { views.iconView.setTag(number); views.iconView.setOnClickListener(this); //views.iconView.setBackgroundResource(R.drawable.call_background); } else { views.iconView.setTag(null); views.iconView.setOnClickListener(null); //views.iconView.setBackgroundResource(0); } // Lookup contacts with this number ContactInfo info = mContactInfo.get(number); if (info == null) { Loading Loading @@ -491,6 +588,7 @@ public class RecentCallsListActivity extends ListActivity // time. For private and unknown numbers: hide it. views.callView.setVisibility(View.VISIBLE); if (!TextUtils.isEmpty(name)) { views.line1View.setText(name); views.labelView.setVisibility(View.VISIBLE); Loading Loading @@ -520,11 +618,77 @@ public class RecentCallsListActivity extends ListActivity number = formatPhoneNumber(number); } //Wysie noContactInfo = true; views.line1View.setText(number); views.numberView.setVisibility(View.GONE); views.labelView.setVisibility(View.GONE); } //Wysie: Contact pictures if (mDisplayPhotos) { long photoId = info.photoId; // Build soft lookup reference final long contactId = info.personId; final String lookupKey = info.lookupKey; Uri contactUri = Contacts.getLookupUri(contactId, lookupKey); ImageView viewToUse; if (noContactInfo) { viewToUse = views.nonQuickContactPhotoView; views.photoView.setVisibility(View.INVISIBLE); views.nonQuickContactPhotoView.setVisibility(View.VISIBLE); } else { viewToUse = views.photoView; //views.photoView.assignContactUri(contactUri); //Wysie: Commented out, we handle it explicityly in onClick() views.photoView.setTag(contactUri); views.photoView.setVisibility(View.VISIBLE); views.nonQuickContactPhotoView.setVisibility(View.INVISIBLE); } final int position = c.getPosition(); viewToUse.setTag(new PhotoInfo(position, photoId, contactUri)); if (photoId == 0) { viewToUse.setImageResource(R.drawable.ic_contact_list_picture); } else { Bitmap photo = null; // Look for the cached bitmap SoftReference<Bitmap> ref = mBitmapCache.get(photoId); if (ref != null) { photo = ref.get(); if (photo == null) { mBitmapCache.remove(photoId); } } // Bind the photo, or use the fallback no photo resource if (photo != null) { viewToUse.setImageBitmap(photo); } else { // Cache miss viewToUse.setImageResource(R.drawable.ic_contact_list_picture); // Add it to a set of images that are populated asynchronously. mItemsMissingImages.add(viewToUse); if (mScrollState != OnScrollListener.SCROLL_STATE_FLING) { // Scrolling is idle or slow, go get the image right now. sendFetchImageMessage(viewToUse); } } } } else { views.photoView.setVisibility(View.GONE); views.nonQuickContactPhotoView.setVisibility(View.GONE); } int type = c.getInt(CALL_TYPE_COLUMN_INDEX); long date = c.getLong(DATE_COLUMN_INDEX); Loading Loading @@ -556,6 +720,14 @@ public class RecentCallsListActivity extends ListActivity views.dateView.setText(DateFormat.format(format, date)); } if (showDialButton) { views.dividerView.setVisibility(View.VISIBLE); views.callView.setVisibility(View.VISIBLE); } else { views.dividerView.setVisibility(View.GONE); views.callView.setVisibility(View.GONE); } // Set the icon switch (type) { case Calls.INCOMING_TYPE: Loading @@ -578,6 +750,161 @@ public class RecentCallsListActivity extends ListActivity view.getViewTreeObserver().addOnPreDrawListener(this); } } //Wysie: Contact pictures private class ImageFetchHandler extends Handler { @Override public void handleMessage(Message message) { if (RecentCallsListActivity.this.isFinishing()) { return; } switch(message.what) { case FETCH_IMAGE_MSG: { final ImageView imageView = (ImageView) message.obj; if (imageView == null) { break; } final PhotoInfo info = (PhotoInfo)imageView.getTag(); if (info == null) { break; } final long photoId = info.photoId; if (photoId == 0) { break; } SoftReference<Bitmap> photoRef = mBitmapCache.get(photoId); if (photoRef == null) { break; } Bitmap photo = photoRef.get(); if (photo == null) { mBitmapCache.remove(photoId); break; } // Make sure the photoId on this image view has not changed // while we were loading the image. synchronized (imageView) { final PhotoInfo updatedInfo = (PhotoInfo)imageView.getTag(); long currentPhotoId = updatedInfo.photoId; if (currentPhotoId == photoId) { imageView.setImageBitmap(photo); mItemsMissingImages.remove(imageView); } } break; } } } public void clearImageFecthing() { removeMessages(FETCH_IMAGE_MSG); } } //Wysie: Contact pictures private class ImageDbFetcher implements Runnable { long mPhotoId; private ImageView mImageView; public ImageDbFetcher(long photoId, ImageView imageView) { this.mPhotoId = photoId; this.mImageView = imageView; } public void run() { if (RecentCallsListActivity.this.isFinishing()) { return; } if (Thread.interrupted()) { // shutdown has been called. return; } Bitmap photo = null; try { photo = ContactsUtils.loadContactPhoto(mContext, mPhotoId, null); } catch (OutOfMemoryError e) { // Not enough memory for the photo, do nothing. } if (photo == null) { return; } mBitmapCache.put(mPhotoId, new SoftReference<Bitmap>(photo)); if (Thread.interrupted()) { // shutdown has been called. return; } // Update must happen on UI thread Message msg = new Message(); msg.what = FETCH_IMAGE_MSG; msg.obj = mImageView; mImageHandler.sendMessage(msg); } } //Wysie: Contact pictures public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // no op } public void onScrollStateChanged(AbsListView view, int scrollState) { mScrollState = scrollState; if (scrollState == OnScrollListener.SCROLL_STATE_FLING) { // If we are in a fling, stop loading images. clearImageFetching(); } else if (mDisplayPhotos) { processMissingImageItems(view); } } private void processMissingImageItems(AbsListView view) { for (ImageView iv : mItemsMissingImages) { sendFetchImageMessage(iv); } } private void sendFetchImageMessage(ImageView view) { final PhotoInfo info = (PhotoInfo) view.getTag(); if (info == null) { return; } final long photoId = info.photoId; if (photoId == 0) { return; } mImageFetcher = new ImageDbFetcher(photoId, view); synchronized (RecentCallsListActivity.this) { // can't sync on sImageFetchThreadPool. if (sImageFetchThreadPool == null) { // Don't use more than 3 threads at a time to update. The thread pool will be // shared by all contact items. sImageFetchThreadPool = Executors.newFixedThreadPool(3); } sImageFetchThreadPool.execute(mImageFetcher); } } public void clearImageFetching() { synchronized (RecentCallsListActivity.this) { if (sImageFetchThreadPool != null) { sImageFetchThreadPool.shutdownNow(); sImageFetchThreadPool = null; } } mImageHandler.clearImageFecthing(); } } private static final class QueryHandler extends AsyncQueryHandler { Loading Loading @@ -638,6 +965,7 @@ public class RecentCallsListActivity extends ListActivity //Wysie ePrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); isQuickContact = false; setContentView(R.layout.recent_calls); Loading @@ -658,23 +986,38 @@ public class RecentCallsListActivity extends ListActivity @Override protected void onResume() { if (isQuickContact) { isQuickContact = false; super.onResume(); } else { // The adapter caches looked up numbers, clear it so they will get // looked up again. if (mAdapter != null) { mAdapter.clearCache(); } // Force cache to reload so we don't show stale photos. if (mAdapter.mBitmapCache != null) { mAdapter.mBitmapCache.clear(); } exactTime = ePrefs.getBoolean("cl_exact_time", true); is24hour = DateFormat.is24HourFormat(this); showSeconds = ePrefs.getBoolean("cl_show_seconds", true); mDisplayPhotos = ePrefs.getBoolean("cl_show_pic", true); showDialButton = ePrefs.getBoolean("cl_show_dial_button", false); super.onResume(); startQuery(); resetNewCallsFlag(); super.onResume(); mScrollState = OnScrollListener.SCROLL_STATE_IDLE; mAdapter.mPreDrawListener = null; // Let it restart the thread after next draw } } @Override protected void onPause() { Loading