diff options
45 files changed, 13 insertions, 2726 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b791d94e4..bcb63adc5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -220,13 +220,13 @@ <!-- Used to filter contacts list by account --> <activity - android:name=".list.AccountFilterActivity" + android:name=".common.list.AccountFilterActivity" android:label="@string/activity_title_contacts_filter" android:theme="@style/ContactListFilterTheme" /> <!-- Used to select display and sync groups --> <activity - android:name=".list.CustomContactListFilterActivity" + android:name=".common.list.CustomContactListFilterActivity" android:label="@string/custom_list_filter" android:theme="@style/ContactListFilterTheme" /> @@ -384,7 +384,7 @@ <!-- Stub service used to keep our process alive long enough for background threads to finish their operations. --> <service - android:name=".util.EmptyService" + android:name=".common.util.EmptyService" android:exported="false" /> <!-- Service to save a contact --> diff --git a/res/drawable-hdpi/badge_action_call.png b/res/drawable-hdpi/badge_action_call.png Binary files differdeleted file mode 100644 index 0b1c6b451..000000000 --- a/res/drawable-hdpi/badge_action_call.png +++ /dev/null diff --git a/res/drawable-hdpi/badge_action_sms.png b/res/drawable-hdpi/badge_action_sms.png Binary files differdeleted file mode 100644 index 0dfdbf5a1..000000000 --- a/res/drawable-hdpi/badge_action_sms.png +++ /dev/null diff --git a/res/drawable-hdpi/ic_menu_settings_holo_light.png b/res/drawable-hdpi/ic_menu_settings_holo_light.png Binary files differdeleted file mode 100644 index b7bb5c414..000000000 --- a/res/drawable-hdpi/ic_menu_settings_holo_light.png +++ /dev/null diff --git a/res/drawable-hdpi/ic_menu_star_holo_light.png b/res/drawable-hdpi/ic_menu_star_holo_light.png Binary files differdeleted file mode 100644 index 45137967c..000000000 --- a/res/drawable-hdpi/ic_menu_star_holo_light.png +++ /dev/null diff --git a/res/drawable-hdpi/unknown_source.png b/res/drawable-hdpi/unknown_source.png Binary files differdeleted file mode 100644 index 0a8f37d7a..000000000 --- a/res/drawable-hdpi/unknown_source.png +++ /dev/null diff --git a/res/drawable-mdpi/badge_action_call.png b/res/drawable-mdpi/badge_action_call.png Binary files differdeleted file mode 100644 index af2abaae8..000000000 --- a/res/drawable-mdpi/badge_action_call.png +++ /dev/null diff --git a/res/drawable-mdpi/badge_action_sms.png b/res/drawable-mdpi/badge_action_sms.png Binary files differdeleted file mode 100644 index 13dd8bc14..000000000 --- a/res/drawable-mdpi/badge_action_sms.png +++ /dev/null diff --git a/res/drawable-mdpi/ic_menu_settings_holo_light.png b/res/drawable-mdpi/ic_menu_settings_holo_light.png Binary files differdeleted file mode 100644 index 1ebc112e7..000000000 --- a/res/drawable-mdpi/ic_menu_settings_holo_light.png +++ /dev/null diff --git a/res/drawable-mdpi/ic_menu_star_holo_light.png b/res/drawable-mdpi/ic_menu_star_holo_light.png Binary files differdeleted file mode 100644 index 8263b27be..000000000 --- a/res/drawable-mdpi/ic_menu_star_holo_light.png +++ /dev/null diff --git a/res/drawable-mdpi/unknown_source.png b/res/drawable-mdpi/unknown_source.png Binary files differdeleted file mode 100644 index 356748f08..000000000 --- a/res/drawable-mdpi/unknown_source.png +++ /dev/null diff --git a/res/drawable-xhdpi/badge_action_call.png b/res/drawable-xhdpi/badge_action_call.png Binary files differdeleted file mode 100644 index 2589e334f..000000000 --- a/res/drawable-xhdpi/badge_action_call.png +++ /dev/null diff --git a/res/drawable-xhdpi/badge_action_sms.png b/res/drawable-xhdpi/badge_action_sms.png Binary files differdeleted file mode 100644 index 460451f95..000000000 --- a/res/drawable-xhdpi/badge_action_sms.png +++ /dev/null diff --git a/res/drawable-xhdpi/ic_menu_settings_holo_light.png b/res/drawable-xhdpi/ic_menu_settings_holo_light.png Binary files differdeleted file mode 100644 index 68ba92bde..000000000 --- a/res/drawable-xhdpi/ic_menu_settings_holo_light.png +++ /dev/null diff --git a/res/drawable-xhdpi/ic_menu_star_holo_light.png b/res/drawable-xhdpi/ic_menu_star_holo_light.png Binary files differdeleted file mode 100644 index 906791177..000000000 --- a/res/drawable-xhdpi/ic_menu_star_holo_light.png +++ /dev/null diff --git a/res/drawable-xhdpi/unknown_source.png b/res/drawable-xhdpi/unknown_source.png Binary files differdeleted file mode 100644 index 35e8fb4a1..000000000 --- a/res/drawable-xhdpi/unknown_source.png +++ /dev/null diff --git a/res/layout/account_filter_header.xml b/res/layout/account_filter_header.xml deleted file mode 100644 index 0ffb7e1cd..000000000 --- a/res/layout/account_filter_header.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- Layout showing the type of account filter - (e.g. All contacts filter, custom filter, etc.), - which is the header of all contact lists. --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/account_filter_header_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingTop="@dimen/list_header_extra_top_padding" - android:layout_marginLeft="@dimen/contact_browser_list_header_left_margin" - android:layout_marginRight="@dimen/contact_browser_list_header_right_margin" - android:background="?android:attr/selectableItemBackground" - android:visibility="gone"> - <TextView - android:id="@+id/account_filter_header" - style="@style/ContactListSeparatorTextViewStyle" - android:paddingLeft="@dimen/contact_browser_list_item_text_indent" /> -</LinearLayout> diff --git a/res/layout/contact_list_content.xml b/res/layout/contact_list_content.xml deleted file mode 100644 index 362209cc8..000000000 --- a/res/layout/contact_list_content.xml +++ /dev/null @@ -1,64 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2008 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!-- android:paddingTop is used instead of android:layout_marginTop. It looks - android:layout_marginTop is ignored when used with <fragment></fragment>, which - only happens in Tablet UI since we rely on ViewPager in Phone UI. - Instead, android:layout_marginTop inside <fragment /> is effective. --> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/pinned_header_list_layout" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="?attr/contact_browser_background" > - - <!-- Shown only when an Account filter is set. - - paddingTop should be here to show "shade" effect correctly. --> - <include - android:id="@+id/account_filter_header_container" - layout="@layout/account_filter_header" /> - - <FrameLayout - android:layout_width="match_parent" - android:layout_height="0dip" - android:layout_weight="1" > - <view - class="com.android.contacts.common.list.PinnedHeaderListView" - android:id="@android:id/list" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginLeft="?attr/contact_browser_list_padding_left" - android:layout_marginRight="?attr/contact_browser_list_padding_right" - android:fastScrollEnabled="true" - android:fadingEdge="none" /> - <ProgressBar - android:id="@+id/search_progress" - style="?android:attr/progressBarStyleLarge" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:visibility="gone" /> - </FrameLayout> - - <ViewStub - android:id="@+id/footer_stub" - android:layout="@layout/footer_panel" - android:layout_width="fill_parent" - android:layout_height="wrap_content" /> - -</LinearLayout> diff --git a/res/layout/contact_list_filter.xml b/res/layout/contact_list_filter.xml deleted file mode 100644 index 37aaf5368..000000000 --- a/res/layout/contact_list_filter.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:fillViewport="true"> - - <ListView - android:id="@android:id/list" - android:layout_width="match_parent" - android:layout_height="0dip" - android:layout_weight="1" - android:layout_marginLeft="@dimen/contact_filter_left_margin" - android:layout_marginRight="@dimen/contact_filter_right_margin" /> - - <View - android:layout_width="match_parent" - android:layout_height="1dip" - android:layout_marginLeft="16dip" - android:layout_marginRight="16dip" - android:background="?android:attr/dividerHorizontal" /> -</LinearLayout> diff --git a/res/layout/contact_list_filter_custom.xml b/res/layout/contact_list_filter_custom.xml deleted file mode 100644 index 40d9c785b..000000000 --- a/res/layout/contact_list_filter_custom.xml +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2007 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - style="@style/CustomContactListFilterView" - android:orientation="vertical" - android:fillViewport="true"> - - <ExpandableListView - android:id="@android:id/list" - android:layout_width="match_parent" - android:layout_height="0dip" - android:layout_weight="1" - android:layout_marginLeft="@dimen/contact_filter_left_margin" - android:layout_marginRight="@dimen/contact_filter_right_margin" - android:overScrollMode="always" /> - - <View - android:layout_width="match_parent" - android:layout_height="1dip" - android:layout_marginLeft="16dip" - android:layout_marginRight="16dip" - android:background="?android:attr/dividerHorizontal" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - style="?android:attr/buttonBarStyle"> - - <Button - android:id="@+id/btn_discard" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@android:string/cancel" /> - - <Button - android:id="@+id/btn_done" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@android:string/ok" /> - - </LinearLayout> -</LinearLayout> diff --git a/res/layout/contact_list_filter_item.xml b/res/layout/contact_list_filter_item.xml deleted file mode 100644 index 781456593..000000000 --- a/res/layout/contact_list_filter_item.xml +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2010 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<view - xmlns:android="http://schemas.android.com/apk/res/android" - class="com.android.contacts.list.ContactListFilterView" - android:descendantFocusability="blocksDescendants" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="@dimen/contact_filter_item_min_height" - android:gravity="center_vertical"> - - <ImageView - android:id="@+id/icon" - android:scaleType="fitCenter" - android:layout_width="@dimen/contact_filter_icon_size" - android:layout_height="@dimen/contact_filter_icon_size"/> - - <LinearLayout - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:orientation="vertical" - android:layout_marginLeft="8dip"> - - <TextView - android:id="@+id/accountType" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceMedium" - android:singleLine="true" - android:ellipsize="end"/> - - <TextView - android:id="@+id/accountUserName" - android:layout_marginTop="-3dip" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="?android:attr/textColorTertiary" - android:singleLine="true" - android:ellipsize="end"/> - </LinearLayout> - - <RadioButton - android:id="@+id/radioButton" - android:clickable="false" - android:layout_marginTop="1dip" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="right|center_vertical" /> -</view> - diff --git a/res/layout/custom_contact_list_filter_account.xml b/res/layout/custom_contact_list_filter_account.xml deleted file mode 100644 index 8c1b6c169..000000000 --- a/res/layout/custom_contact_list_filter_account.xml +++ /dev/null @@ -1,56 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeight" - android:gravity="center_vertical" - android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" - android:paddingRight="?android:attr/scrollbarSize"> - - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginRight="6dip" - android:layout_marginTop="6dip" - android:layout_marginBottom="6dip" - android:layout_weight="1" - android:duplicateParentState="true"> - - <TextView - android:id="@android:id/text1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:ellipsize="marquee" - android:textAppearance="?android:attr/textAppearanceMedium" - android:duplicateParentState="true" /> - - <TextView - android:id="@android:id/text2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@android:id/text1" - android:layout_alignLeft="@android:id/text1" - android:maxLines="1" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="?android:attr/textColorTertiary" - android:duplicateParentState="true" /> - - </RelativeLayout> - -</LinearLayout> diff --git a/res/layout/custom_contact_list_filter_group.xml b/res/layout/custom_contact_list_filter_group.xml deleted file mode 100644 index 65ef40555..000000000 --- a/res/layout/custom_contact_list_filter_group.xml +++ /dev/null @@ -1,71 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeight" - android:gravity="center_vertical" - android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" - android:paddingRight="?android:attr/scrollbarSize" -> - - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginRight="6dip" - android:layout_marginTop="6dip" - android:layout_marginBottom="6dip" - android:layout_weight="1" - android:duplicateParentState="true" - > - - <TextView - android:id="@android:id/text1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:ellipsize="marquee" - android:textAppearance="?android:attr/textAppearanceMedium" - android:duplicateParentState="true" - /> - - <TextView - android:id="@android:id/text2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@android:id/text1" - android:layout_alignLeft="@android:id/text1" - android:maxLines="2" - android:textAppearance="?android:attr/textAppearanceSmall" - android:duplicateParentState="true" - /> - - </RelativeLayout> - - <CheckBox - android:id="@android:id/checkbox" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginRight="4dip" - android:focusable="false" - android:clickable="false" - android:gravity="center_vertical" - android:orientation="vertical" - android:duplicateParentState="true" - /> - -</LinearLayout> diff --git a/res/layout/footer_panel.xml b/res/layout/footer_panel.xml deleted file mode 100644 index 2625a43e9..000000000 --- a/res/layout/footer_panel.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/footer" - android:orientation="horizontal" - android:visibility="gone" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:gravity="center" - style="@android:style/ButtonBar" -> - - <Button android:id="@+id/done" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/menu_done" - /> - - <Button android:id="@+id/revert" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/menu_doNotSave" - /> - -</LinearLayout>
\ No newline at end of file diff --git a/res/values-sw580dp/dimens.xml b/res/values-sw580dp/dimens.xml index d3a9bea88..4c4505c83 100644 --- a/res/values-sw580dp/dimens.xml +++ b/res/values-sw580dp/dimens.xml @@ -31,8 +31,6 @@ <dimen name="quick_contact_top_position">-1px</dimen> <!-- Contact list (vertical scroll bar comes left) --> <dimen name="contact_browser_list_top_margin">16dip</dimen> - <dimen name="contact_browser_list_header_left_margin">@dimen/list_visible_scrollbar_padding</dimen> - <dimen name="contact_browser_list_header_right_margin">24dip</dimen> <dimen name="list_visible_scrollbar_padding">32dip</dimen> <dimen name="list_header_extra_top_padding">@dimen/contact_browser_list_top_margin</dimen> diff --git a/res/values-sw580dp/styles.xml b/res/values-sw580dp/styles.xml index 1181d5def..ce0ec1553 100644 --- a/res/values-sw580dp/styles.xml +++ b/res/values-sw580dp/styles.xml @@ -97,16 +97,6 @@ <item name="android:windowSoftInputMode">adjustUnspecified</item> </style> - <style name="ContactListFilterTheme" parent="@android:Theme.Holo.Light.Dialog"> - <item name="android:windowCloseOnTouchOutside">true</item> - <item name="android:listViewStyle">@style/ListViewStyle</item> - </style> - - <style name="CustomContactListFilterView" parent="ContactListFilterTheme"> - <item name="android:layout_width">match_parent</item> - <item name="android:layout_height">400dip</item> - </style> - <style name="DetailActivityTheme" parent="@android:Theme.Dialog"> <item name="android:windowContentOverlay">@null</item> </style> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 9f8ce8370..d7845c45e 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -56,12 +56,6 @@ <attr name="ratio" format="float"/> </declare-styleable> - <declare-styleable name="ContactBrowser"> - <attr name="contact_browser_list_padding_left" format="dimension"/> - <attr name="contact_browser_list_padding_right" format="dimension"/> - <attr name="contact_browser_background" format="reference"/> - </declare-styleable> - <declare-styleable name="Favorites"> <attr name="favorites_padding_bottom" format="dimension" /> </declare-styleable> diff --git a/res/values/colors.xml b/res/values/colors.xml index 7a99cc342..99e917b8d 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -14,10 +14,6 @@ limitations under the License. --> <resources> - <color name="textColorIconOverlay">#fff</color> - <color name="textColorIconOverlayShadow">#000</color> - - <color name="shortcut_overlay_text_background">#7f000000</color> <color name="quickcontact_list_divider">#ffcdcdcd</color> <color name="quickcontact_list_background">#ffe2e2e2</color> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index d22bf6460..aaad3132a 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -91,27 +91,12 @@ (phone number, email, etc.) and a secondary action button --> <dimen name="detail_vertical_divider_vertical_margin">16dip</dimen> - <!-- Padding to be used between a visible scrollbar and the contact list --> - <dimen name="list_visible_scrollbar_padding">32dip</dimen> - <!-- Font size used for the contact name in the widget --> <dimen name="widget_text_size_name">14sp</dimen> <!-- Font size used for the social status in the widget --> <dimen name="widget_text_size_snippet">13sp</dimen> - <!-- Size of the shortcut icon. 0dip means: use the system default --> - <dimen name="shortcut_icon_size">0dip</dimen> - - <!-- Width of darkened border for shortcut icon --> - <dimen name="shortcut_icon_border_width">1dp</dimen> - - <!-- Text size of shortcut icon overlay text --> - <dimen name="shortcut_overlay_text_size">12dp</dimen> - - <!-- Extra vertical padding for darkened background behind shortcut icon overlay text --> - <dimen name="shortcut_overlay_text_background_padding">1dp</dimen> - <!-- Height of list sections (A, B, C) that show the first character of the contacts --> <dimen name="list_section_height">25dip</dimen> @@ -143,10 +128,7 @@ <dimen name="search_view_width">0dip</dimen> <!-- contact browser list margins --> - <dimen name="contact_browser_list_header_left_margin">16dip</dimen> - <dimen name="contact_browser_list_header_right_margin">@dimen/list_visible_scrollbar_padding</dimen> <dimen name="contact_browser_list_item_photo_size">64dip</dimen> - <dimen name="contact_browser_list_item_text_indent">8dip</dimen> <dimen name="contact_browser_list_top_margin">8dip</dimen> <!-- For join screen. Mainly for tablet. --> <dimen name="join_header_left_margin">@dimen/contact_browser_list_header_left_margin</dimen> @@ -158,11 +140,6 @@ <dimen name="empty_message_top_margin">48dip</dimen> <dimen name="no_accounts_message_margin">20dip</dimen> - <!-- For contact filter setting screens --> - <dimen name="contact_filter_left_margin">16dip</dimen> - <dimen name="contact_filter_right_margin">16dip</dimen> - <dimen name="contact_filter_item_min_height">48dip</dimen> - <dimen name="contact_filter_icon_size">32dip</dimen> <dimen name="contact_filter_header_min_height">24dip</dimen> <!-- Width of the lead margin on the left of a block quote inside a stream item --> diff --git a/res/values/strings.xml b/res/values/strings.xml index 832750b3d..aadd05c51 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -184,12 +184,6 @@ <!-- Confirmation dialog contents after users selects to delete a Writable contact. --> <string name="deleteConfirmation">This contact will be deleted.</string> - <!-- Menu item to indicate you are done editing a contact and want to save the changes you've made --> - <string name="menu_done">Done</string> - - <!-- Menu item to indicate you want to cancel the current editing process and NOT save the changes you've made [CHAR LIMIT=12] --> - <string name="menu_doNotSave">Cancel</string> - <!-- Menu item to indicate you want to stop editing a contact and NOT save the changes you've made [CHAR LIMIT=12] --> <string name="menu_discard">Discard</string> @@ -255,9 +249,6 @@ <!-- Displayed in a spinner dialog after the user creates a contact and it's being saved to the database --> <string name="savingContact">Saving contact\u2026</string> - <!-- Displayed in a spinner dialog as user changes to display options are saved --> - <string name="savingDisplayGroups">Saving display options\u2026</string> - <!-- Toast displayed when a contact is saved [CHAR LIMIT=NONE] --> <string name="contactSavedToast">Contact saved.</string> @@ -297,15 +288,6 @@ <!-- Displayed at the top of the contacts showing the zero total number of contacts visible when a group or account is selected [CHAR LIMIT=64]--> <string name="listTotalAllContactsZeroGroup">No contacts in <xliff:g id="name" example="Friends">%s</xliff:g></string> - <!-- Displayed at the top of the contacts showing the account filter selected [CHAR LIMIT=64] --> - <string name="listAllContactsInAccount">Contacts in <xliff:g id="name" example="abc@gmail.com">%s</xliff:g></string> - - <!-- Displayed at the top of the contacts showing single contact. [CHAR LIMIT=64] --> - <string name="listSingleContact">Single contact</string> - - <!-- Displayed at the top of the contacts showing single contact. [CHAR LIMIT=64] --> - <string name="listCustomView">Contacts in custom view</string> - <!-- Displayed at the top of the contacts showing the total number of contacts found when "Only contacts with phones" not selected [CHAR LIMIT=30] --> <plurals name="listFoundAllContacts"> <item quantity="one">1 found</item> @@ -842,21 +824,6 @@ <!-- Title for the disambiguation dialog that requests the user choose an account for the new group to be created under [CHAR LIMIT=NONE] --> <string name="dialog_new_group_account">Create group under account</string> - <string name="menu_sync_remove">Remove sync group</string> - <string name="dialog_sync_add">Add sync group</string> - <string name="display_more_groups">More groups\u2026</string> - - <!-- List title for a special contacts group that covers all contacts. [CHAR LIMIT=25] --> - <string name="display_ungrouped">All other contacts</string> - - <!-- List title for a special contacts group that covers all contacts that - aren't members of any other group. [CHAR LIMIT=25] --> - <string name="display_all_contacts">All contacts</string> - - <!-- Warning message given to users just before they remove a currently syncing - group that would also cause all ungrouped contacts to stop syncing. [CHAR LIMIT=NONE] --> - <string name="display_warn_remove_ungrouped">Removing \"<xliff:g id="group" example="Starred">%s</xliff:g>\" from sync will also remove any ungrouped contacts from sync.</string> - <!-- Generic action string for starting an audio chat. Used by AccessibilityService to announce the purpose of the view. [CHAR LIMIT=NONE] --> <string name="audio_chat">Voice chat</string> <!-- Generic action string for starting a video chat. Used by AccessibilityService to announce the purpose of the view. [CHAR LIMIT=NONE] --> @@ -1016,21 +983,9 @@ <!-- Toast shown when creating a personal copy of a contact [CHAR LIMIT=100] --> <string name="toast_making_personal_copy">Creating a personal copy\u2026</string> - <!-- Contact list filter label indicating that the list is showing all available accounts [CHAR LIMIT=64] --> - <string name="list_filter_all_accounts">All contacts</string> - - <!-- Contact list filter label indicating that the list is showing all starred contacts [CHAR LIMIT=64] --> - <string name="list_filter_all_starred">Starred</string> - <!-- Contact list filter indicating that the list shows groups chosen by the user [CHAR LIMIT=64] --> <string name="list_filter_custom">Custom</string> - <!-- Contact list filter selection indicating that the list shows groups chosen by the user [CHAR LIMIT=64] --> - <string name="list_filter_customize">Customize</string> - - <!-- Contact list filter selection indicating that the list shows only the selected contact [CHAR LIMIT=64] --> - <string name="list_filter_single">Contact</string> - <!-- Title of the activity that allows the user to customize filtering of contact list [CHAR LIMIT=128] --> <string name="custom_list_filter">Define custom view</string> diff --git a/res/values/styles.xml b/res/values/styles.xml index 3d7da3709..6208018d4 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -126,10 +126,6 @@ <item name="android:listSelector">?android:attr/listChoiceBackgroundIndicator</item> </style> - <style name="ListViewStyle" parent="@android:style/Widget.Holo.Light.ListView"> - <item name="android:overScrollMode">always</item> - </style> - <style name="ContactPickerTheme" parent="@style/PeopleTheme" /> <style name="ContactPickerLayout" parent="ContactPickerTheme"> @@ -148,11 +144,6 @@ <item name="android:listViewStyle">@style/ListViewStyle</item> </style> - <style name="CustomContactListFilterView" parent="ContactListFilterTheme"> - <item name="android:layout_width">match_parent</item> - <item name="android:layout_height">match_parent</item> - </style> - <style name="NonPhoneActivityTheme" parent="@android:Theme.Translucent.NoTitleBar"> </style> diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java index 40606e018..ae4cf9447 100644 --- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java +++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java @@ -71,7 +71,7 @@ import com.android.contacts.common.model.account.AccountType; import com.android.contacts.common.model.account.AccountWithDataSet; import com.android.contacts.common.model.dataitem.DataKind; import com.android.contacts.util.DialogManager; -import com.android.contacts.util.EmptyService; +import com.android.contacts.common.util.EmptyService; import java.lang.ref.WeakReference; import java.util.ArrayList; diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java index 927e429a4..6275a990e 100644 --- a/src/com/android/contacts/activities/PeopleActivity.java +++ b/src/com/android/contacts/activities/PeopleActivity.java @@ -83,7 +83,7 @@ import com.android.contacts.model.Contact; import com.android.contacts.common.model.account.AccountWithDataSet; import com.android.contacts.preference.ContactsPreferenceActivity; import com.android.contacts.preference.DisplayOptionsPreferenceFragment; -import com.android.contacts.util.AccountFilterUtil; +import com.android.contacts.common.util.AccountFilterUtil; import com.android.contacts.util.AccountPromptUtils; import com.android.contacts.common.util.Constants; import com.android.contacts.util.DialogManager; diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java index c23e23910..a239d47f3 100644 --- a/src/com/android/contacts/detail/ContactLoaderFragment.java +++ b/src/com/android/contacts/detail/ContactLoaderFragment.java @@ -42,8 +42,8 @@ import android.widget.Toast; import com.android.contacts.ContactSaveService; import com.android.contacts.R; import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener; -import com.android.contacts.list.ShortcutIntentBuilder; -import com.android.contacts.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; +import com.android.contacts.common.list.ShortcutIntentBuilder; +import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; import com.android.contacts.model.Contact; import com.android.contacts.model.ContactLoader; import com.android.contacts.util.PhoneCapabilityTester; diff --git a/src/com/android/contacts/list/AccountFilterActivity.java b/src/com/android/contacts/list/AccountFilterActivity.java deleted file mode 100644 index b6f931064..000000000 --- a/src/com/android/contacts/list/AccountFilterActivity.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.contacts.list; - -import android.app.ActionBar; -import android.app.Activity; -import android.app.LoaderManager.LoaderCallbacks; -import android.content.AsyncTaskLoader; -import android.content.Context; -import android.content.Intent; -import android.content.Loader; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.ListView; - -import com.android.contacts.ContactsActivity; -import com.android.contacts.R; -import com.android.contacts.common.list.ContactListFilter; -import com.android.contacts.common.model.AccountTypeManager; -import com.android.contacts.common.model.account.AccountType; -import com.android.contacts.common.model.account.AccountWithDataSet; -import com.google.common.collect.Lists; - -import java.util.ArrayList; -import java.util.List; - -/** - * Shows a list of all available accounts, letting the user select under which account to view - * contacts. - */ -public class AccountFilterActivity extends ContactsActivity - implements AdapterView.OnItemClickListener { - - private static final String TAG = AccountFilterActivity.class.getSimpleName(); - - private static final int SUBACTIVITY_CUSTOMIZE_FILTER = 0; - - public static final String KEY_EXTRA_CONTACT_LIST_FILTER = "contactListFilter"; - public static final String KEY_EXTRA_CURRENT_FILTER = "currentFilter"; - - private static final int FILTER_LOADER_ID = 0; - - private ListView mListView; - - private ContactListFilter mCurrentFilter; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.contact_list_filter); - - mListView = (ListView) findViewById(android.R.id.list); - mListView.setOnItemClickListener(this); - - ActionBar actionBar = getActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - } - - mCurrentFilter = getIntent().getParcelableExtra(KEY_EXTRA_CURRENT_FILTER); - - getLoaderManager().initLoader(FILTER_LOADER_ID, null, new MyLoaderCallbacks()); - } - - private static class FilterLoader extends AsyncTaskLoader<List<ContactListFilter>> { - private Context mContext; - - public FilterLoader(Context context) { - super(context); - mContext = context; - } - - @Override - public List<ContactListFilter> loadInBackground() { - return loadAccountFilters(mContext); - } - - @Override - protected void onStartLoading() { - forceLoad(); - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - protected void onReset() { - onStopLoading(); - } - } - - private static List<ContactListFilter> loadAccountFilters(Context context) { - final ArrayList<ContactListFilter> result = Lists.newArrayList(); - final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList(); - final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context); - List<AccountWithDataSet> accounts = accountTypes.getAccounts(false); - for (AccountWithDataSet account : accounts) { - AccountType accountType = accountTypes.getAccountType(account.type, account.dataSet); - if (accountType.isExtension() && !account.hasData(context)) { - // Hide extensions with no raw_contacts. - continue; - } - Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null; - accountFilters.add(ContactListFilter.createAccountFilter( - account.type, account.name, account.dataSet, icon)); - } - - // Always show "All", even when there's no accounts. (We may have local contacts) - result.add(ContactListFilter.createFilterWithType( - ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS)); - - final int count = accountFilters.size(); - if (count >= 1) { - // If we only have one account, don't show it as "account", instead show it as "all" - if (count > 1) { - result.addAll(accountFilters); - } - result.add(ContactListFilter.createFilterWithType( - ContactListFilter.FILTER_TYPE_CUSTOM)); - } - return result; - } - - private class MyLoaderCallbacks implements LoaderCallbacks<List<ContactListFilter>> { - @Override - public Loader<List<ContactListFilter>> onCreateLoader(int id, Bundle args) { - return new FilterLoader(AccountFilterActivity.this); - } - - @Override - public void onLoadFinished( - Loader<List<ContactListFilter>> loader, List<ContactListFilter> data) { - if (data == null) { // Just in case... - Log.e(TAG, "Failed to load filters"); - return; - } - mListView.setAdapter( - new FilterListAdapter(AccountFilterActivity.this, data, mCurrentFilter)); - } - - @Override - public void onLoaderReset(Loader<List<ContactListFilter>> loader) { - } - } - - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - final ContactListFilter filter = (ContactListFilter) view.getTag(); - if (filter == null) return; // Just in case - if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) { - final Intent intent = new Intent(this, - CustomContactListFilterActivity.class); - startActivityForResult(intent, SUBACTIVITY_CUSTOMIZE_FILTER); - } else { - final Intent intent = new Intent(); - intent.putExtra(KEY_EXTRA_CONTACT_LIST_FILTER, filter); - setResult(Activity.RESULT_OK, intent); - finish(); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode != Activity.RESULT_OK) { - return; - } - - switch (requestCode) { - case SUBACTIVITY_CUSTOMIZE_FILTER: { - final Intent intent = new Intent(); - ContactListFilter filter = ContactListFilter.createFilterWithType( - ContactListFilter.FILTER_TYPE_CUSTOM); - intent.putExtra(KEY_EXTRA_CONTACT_LIST_FILTER, filter); - setResult(Activity.RESULT_OK, intent); - finish(); - break; - } - } - } - - private static class FilterListAdapter extends BaseAdapter { - private final List<ContactListFilter> mFilters; - private final LayoutInflater mLayoutInflater; - private final AccountTypeManager mAccountTypes; - private final ContactListFilter mCurrentFilter; - - public FilterListAdapter( - Context context, List<ContactListFilter> filters, ContactListFilter current) { - mLayoutInflater = (LayoutInflater) context.getSystemService - (Context.LAYOUT_INFLATER_SERVICE); - mFilters = filters; - mCurrentFilter = current; - mAccountTypes = AccountTypeManager.getInstance(context); - } - - @Override - public int getCount() { - return mFilters.size(); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public ContactListFilter getItem(int position) { - return mFilters.get(position); - } - - public View getView(int position, View convertView, ViewGroup parent) { - final ContactListFilterView view; - if (convertView != null) { - view = (ContactListFilterView) convertView; - } else { - view = (ContactListFilterView) mLayoutInflater.inflate( - R.layout.contact_list_filter_item, parent, false); - } - view.setSingleAccount(mFilters.size() == 1); - final ContactListFilter filter = mFilters.get(position); - view.setContactListFilter(filter); - view.bindView(mAccountTypes); - view.setTag(filter); - view.setActivated(filter.equals(mCurrentFilter)); - return view; - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // We have two logical "up" Activities: People and Phone. - // Instead of having one static "up" direction, behave like back as an - // exceptional case. - onBackPressed(); - return true; - default: - break; - } - return super.onOptionsItemSelected(item); - } -} diff --git a/src/com/android/contacts/list/ContactListFilterView.java b/src/com/android/contacts/list/ContactListFilterView.java deleted file mode 100644 index 5fa8e4d69..000000000 --- a/src/com/android/contacts/list/ContactListFilterView.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.contacts.list; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RadioButton; -import android.widget.TextView; - -import com.android.contacts.R; -import com.android.contacts.common.list.ContactListFilter; -import com.android.contacts.common.model.AccountTypeManager; -import com.android.contacts.common.model.account.AccountType; - -/** - * Contact list filter parameters. - */ -public class ContactListFilterView extends LinearLayout { - - private static final String TAG = ContactListFilterView.class.getSimpleName(); - - private ImageView mIcon; - private TextView mAccountType; - private TextView mAccountUserName; - private RadioButton mRadioButton; - private ContactListFilter mFilter; - private boolean mSingleAccount; - - public ContactListFilterView(Context context) { - super(context); - } - - public ContactListFilterView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void setContactListFilter(ContactListFilter filter) { - mFilter = filter; - } - - public ContactListFilter getContactListFilter() { - return mFilter; - } - - public void setSingleAccount(boolean flag) { - this.mSingleAccount = flag; - } - - @Override - public void setActivated(boolean activated) { - super.setActivated(activated); - if (mRadioButton != null) { - mRadioButton.setChecked(activated); - } else { - // We're guarding against null-pointer exceptions, - // but otherwise this code is not expected to work - // properly if the button hasn't been initialized. - Log.wtf(TAG, "radio-button cannot be activated because it is null"); - } - } - - public void bindView(AccountTypeManager accountTypes) { - if (mAccountType == null) { - mIcon = (ImageView) findViewById(R.id.icon); - mAccountType = (TextView) findViewById(R.id.accountType); - mAccountUserName = (TextView) findViewById(R.id.accountUserName); - mRadioButton = (RadioButton) findViewById(R.id.radioButton); - mRadioButton.setChecked(isActivated()); - } - - if (mFilter == null) { - mAccountType.setText(R.string.contactsList); - return; - } - - mAccountUserName.setVisibility(View.GONE); - switch (mFilter.filterType) { - case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS: { - bindView(0, R.string.list_filter_all_accounts); - break; - } - case ContactListFilter.FILTER_TYPE_STARRED: { - bindView(R.drawable.ic_menu_star_holo_light, R.string.list_filter_all_starred); - break; - } - case ContactListFilter.FILTER_TYPE_CUSTOM: { - bindView(R.drawable.ic_menu_settings_holo_light, R.string.list_filter_customize); - break; - } - case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY: { - bindView(0, R.string.list_filter_phones); - break; - } - case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT: { - bindView(0, R.string.list_filter_single); - break; - } - case ContactListFilter.FILTER_TYPE_ACCOUNT: { - mAccountUserName.setVisibility(View.VISIBLE); - mIcon.setVisibility(View.VISIBLE); - if (mFilter.icon != null) { - mIcon.setImageDrawable(mFilter.icon); - } else { - mIcon.setImageResource(R.drawable.unknown_source); - } - final AccountType accountType = - accountTypes.getAccountType(mFilter.accountType, mFilter.dataSet); - mAccountUserName.setText(mFilter.accountName); - mAccountType.setText(accountType.getDisplayLabel(getContext())); - break; - } - } - } - - private void bindView(int iconResource, int textResource) { - if (iconResource != 0) { - mIcon.setVisibility(View.VISIBLE); - mIcon.setImageResource(iconResource); - } else { - mIcon.setVisibility(View.GONE); - } - - mAccountType.setText(textResource); - } -} diff --git a/src/com/android/contacts/list/ContactPickerFragment.java b/src/com/android/contacts/list/ContactPickerFragment.java index acc142ea4..c8ad712a7 100644 --- a/src/com/android/contacts/list/ContactPickerFragment.java +++ b/src/com/android/contacts/list/ContactPickerFragment.java @@ -29,7 +29,8 @@ import com.android.contacts.common.list.ContactListAdapter; import com.android.contacts.common.list.ContactListFilter; import com.android.contacts.common.list.DefaultContactListAdapter; import com.android.contacts.common.list.DirectoryListLoader; -import com.android.contacts.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; +import com.android.contacts.common.list.ShortcutIntentBuilder; +import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; /** * Fragment for the contact list used for browsing contacts (as compared to diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java deleted file mode 100644 index addb04224..000000000 --- a/src/com/android/contacts/list/CustomContactListFilterActivity.java +++ /dev/null @@ -1,924 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.contacts.list; - -import android.app.ActionBar; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.LoaderManager.LoaderCallbacks; -import android.app.ProgressDialog; -import android.content.AsyncTaskLoader; -import android.content.ContentProviderOperation; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.Loader; -import android.content.OperationApplicationException; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.RemoteException; -import android.preference.PreferenceManager; -import android.provider.ContactsContract; -import android.provider.ContactsContract.Groups; -import android.provider.ContactsContract.Settings; -import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseExpandableListAdapter; -import android.widget.CheckBox; -import android.widget.ExpandableListAdapter; -import android.widget.ExpandableListView; -import android.widget.ExpandableListView.ExpandableListContextMenuInfo; -import android.widget.TextView; - -import com.android.contacts.ContactsActivity; -import com.android.contacts.R; -import com.android.contacts.common.model.AccountTypeManager; -import com.android.contacts.common.model.ValuesDelta; -import com.android.contacts.common.model.account.AccountType; -import com.android.contacts.common.model.account.AccountWithDataSet; -import com.android.contacts.common.model.account.GoogleAccountType; -import com.android.contacts.util.EmptyService; -import com.android.contacts.util.LocalizedNameResolver; -import com.android.contacts.util.WeakAsyncTask; -import com.google.common.collect.Lists; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; - -/** - * Shows a list of all available {@link Groups} available, letting the user - * select which ones they want to be visible. - */ -public class CustomContactListFilterActivity extends ContactsActivity - implements View.OnClickListener, ExpandableListView.OnChildClickListener, - LoaderCallbacks<CustomContactListFilterActivity.AccountSet> -{ - private static final String TAG = "CustomContactListFilterActivity"; - - private static final int ACCOUNT_SET_LOADER_ID = 1; - - private ExpandableListView mList; - private DisplayAdapter mAdapter; - - private SharedPreferences mPrefs; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.contact_list_filter_custom); - - mList = (ExpandableListView) findViewById(android.R.id.list); - mList.setOnChildClickListener(this); - mList.setHeaderDividersEnabled(true); - mPrefs = PreferenceManager.getDefaultSharedPreferences(this); - mAdapter = new DisplayAdapter(this); - - final LayoutInflater inflater = getLayoutInflater(); - - findViewById(R.id.btn_done).setOnClickListener(this); - findViewById(R.id.btn_discard).setOnClickListener(this); - - mList.setOnCreateContextMenuListener(this); - - mList.setAdapter(mAdapter); - - ActionBar actionBar = getActionBar(); - if (actionBar != null) { - // android.R.id.home will be triggered in onOptionsItemSelected() - actionBar.setDisplayHomeAsUpEnabled(true); - } - } - - public static class CustomFilterConfigurationLoader extends AsyncTaskLoader<AccountSet> { - - private AccountSet mAccountSet; - - public CustomFilterConfigurationLoader(Context context) { - super(context); - } - - @Override - public AccountSet loadInBackground() { - Context context = getContext(); - final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context); - final ContentResolver resolver = context.getContentResolver(); - - final AccountSet accounts = new AccountSet(); - for (AccountWithDataSet account : accountTypes.getAccounts(false)) { - final AccountType accountType = accountTypes.getAccountTypeForAccount(account); - if (accountType.isExtension() && !account.hasData(context)) { - // Extension with no data -- skip. - continue; - } - - AccountDisplay accountDisplay = - new AccountDisplay(resolver, account.name, account.type, account.dataSet); - - final Uri.Builder groupsUri = Groups.CONTENT_URI.buildUpon() - .appendQueryParameter(Groups.ACCOUNT_NAME, account.name) - .appendQueryParameter(Groups.ACCOUNT_TYPE, account.type); - if (account.dataSet != null) { - groupsUri.appendQueryParameter(Groups.DATA_SET, account.dataSet).build(); - } - android.content.EntityIterator iterator = - ContactsContract.Groups.newEntityIterator(resolver.query( - groupsUri.build(), null, null, null, null)); - try { - boolean hasGroups = false; - - // Create entries for each known group - while (iterator.hasNext()) { - final ContentValues values = iterator.next().getEntityValues(); - final GroupDelta group = GroupDelta.fromBefore(values); - accountDisplay.addGroup(group); - hasGroups = true; - } - // Create single entry handling ungrouped status - accountDisplay.mUngrouped = - GroupDelta.fromSettings(resolver, account.name, account.type, - account.dataSet, hasGroups); - accountDisplay.addGroup(accountDisplay.mUngrouped); - } finally { - iterator.close(); - } - - accounts.add(accountDisplay); - } - - return accounts; - } - - @Override - public void deliverResult(AccountSet cursor) { - if (isReset()) { - return; - } - - mAccountSet = cursor; - - if (isStarted()) { - super.deliverResult(cursor); - } - } - - @Override - protected void onStartLoading() { - if (mAccountSet != null) { - deliverResult(mAccountSet); - } - if (takeContentChanged() || mAccountSet == null) { - forceLoad(); - } - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - protected void onReset() { - super.onReset(); - onStopLoading(); - mAccountSet = null; - } - } - - @Override - protected void onStart() { - getLoaderManager().initLoader(ACCOUNT_SET_LOADER_ID, null, this); - super.onStart(); - } - - @Override - public Loader<AccountSet> onCreateLoader(int id, Bundle args) { - return new CustomFilterConfigurationLoader(this); - } - - @Override - public void onLoadFinished(Loader<AccountSet> loader, AccountSet data) { - mAdapter.setAccounts(data); - } - - @Override - public void onLoaderReset(Loader<AccountSet> loader) { - mAdapter.setAccounts(null); - } - - private static final int DEFAULT_SHOULD_SYNC = 1; - private static final int DEFAULT_VISIBLE = 0; - - /** - * Entry holding any changes to {@link Groups} or {@link Settings} rows, - * such as {@link Groups#SHOULD_SYNC} or {@link Groups#GROUP_VISIBLE}. - */ - protected static class GroupDelta extends ValuesDelta { - private boolean mUngrouped = false; - private boolean mAccountHasGroups; - - private GroupDelta() { - super(); - } - - /** - * Build {@link GroupDelta} from the {@link Settings} row for the given - * {@link Settings#ACCOUNT_NAME}, {@link Settings#ACCOUNT_TYPE}, and - * {@link Settings#DATA_SET}. - */ - public static GroupDelta fromSettings(ContentResolver resolver, String accountName, - String accountType, String dataSet, boolean accountHasGroups) { - final Uri.Builder settingsUri = Settings.CONTENT_URI.buildUpon() - .appendQueryParameter(Settings.ACCOUNT_NAME, accountName) - .appendQueryParameter(Settings.ACCOUNT_TYPE, accountType); - if (dataSet != null) { - settingsUri.appendQueryParameter(Settings.DATA_SET, dataSet); - } - final Cursor cursor = resolver.query(settingsUri.build(), new String[] { - Settings.SHOULD_SYNC, Settings.UNGROUPED_VISIBLE - }, null, null, null); - - try { - final ContentValues values = new ContentValues(); - values.put(Settings.ACCOUNT_NAME, accountName); - values.put(Settings.ACCOUNT_TYPE, accountType); - values.put(Settings.DATA_SET, dataSet); - - if (cursor != null && cursor.moveToFirst()) { - // Read existing values when present - values.put(Settings.SHOULD_SYNC, cursor.getInt(0)); - values.put(Settings.UNGROUPED_VISIBLE, cursor.getInt(1)); - return fromBefore(values).setUngrouped(accountHasGroups); - } else { - // Nothing found, so treat as create - values.put(Settings.SHOULD_SYNC, DEFAULT_SHOULD_SYNC); - values.put(Settings.UNGROUPED_VISIBLE, DEFAULT_VISIBLE); - return fromAfter(values).setUngrouped(accountHasGroups); - } - } finally { - if (cursor != null) cursor.close(); - } - } - - public static GroupDelta fromBefore(ContentValues before) { - final GroupDelta entry = new GroupDelta(); - entry.mBefore = before; - entry.mAfter = new ContentValues(); - return entry; - } - - public static GroupDelta fromAfter(ContentValues after) { - final GroupDelta entry = new GroupDelta(); - entry.mBefore = null; - entry.mAfter = after; - return entry; - } - - protected GroupDelta setUngrouped(boolean accountHasGroups) { - mUngrouped = true; - mAccountHasGroups = accountHasGroups; - return this; - } - - @Override - public boolean beforeExists() { - return mBefore != null; - } - - public boolean getShouldSync() { - return getAsInteger(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC, - DEFAULT_SHOULD_SYNC) != 0; - } - - public boolean getVisible() { - return getAsInteger(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE, - DEFAULT_VISIBLE) != 0; - } - - public void putShouldSync(boolean shouldSync) { - put(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC, shouldSync ? 1 : 0); - } - - public void putVisible(boolean visible) { - put(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE, visible ? 1 : 0); - } - - private String getAccountType() { - return (mBefore == null ? mAfter : mBefore).getAsString(Settings.ACCOUNT_TYPE); - } - - public CharSequence getTitle(Context context) { - if (mUngrouped) { - final String customAllContactsName = - LocalizedNameResolver.getAllContactsName(context, getAccountType()); - if (customAllContactsName != null) { - return customAllContactsName; - } - if (mAccountHasGroups) { - return context.getText(R.string.display_ungrouped); - } else { - return context.getText(R.string.display_all_contacts); - } - } else { - final Integer titleRes = getAsInteger(Groups.TITLE_RES); - if (titleRes != null) { - final String packageName = getAsString(Groups.RES_PACKAGE); - return context.getPackageManager().getText(packageName, titleRes, null); - } else { - return getAsString(Groups.TITLE); - } - } - } - - /** - * Build a possible {@link ContentProviderOperation} to persist any - * changes to the {@link Groups} or {@link Settings} row described by - * this {@link GroupDelta}. - */ - public ContentProviderOperation buildDiff() { - if (isInsert()) { - // Only allow inserts for Settings - if (mUngrouped) { - mAfter.remove(mIdColumn); - return ContentProviderOperation.newInsert(Settings.CONTENT_URI) - .withValues(mAfter) - .build(); - } - else { - throw new IllegalStateException("Unexpected diff"); - } - } else if (isUpdate()) { - if (mUngrouped) { - String accountName = this.getAsString(Settings.ACCOUNT_NAME); - String accountType = this.getAsString(Settings.ACCOUNT_TYPE); - String dataSet = this.getAsString(Settings.DATA_SET); - StringBuilder selection = new StringBuilder(Settings.ACCOUNT_NAME + "=? AND " - + Settings.ACCOUNT_TYPE + "=?"); - String[] selectionArgs; - if (dataSet == null) { - selection.append(" AND " + Settings.DATA_SET + " IS NULL"); - selectionArgs = new String[] {accountName, accountType}; - } else { - selection.append(" AND " + Settings.DATA_SET + "=?"); - selectionArgs = new String[] {accountName, accountType, dataSet}; - } - return ContentProviderOperation.newUpdate(Settings.CONTENT_URI) - .withSelection(selection.toString(), selectionArgs) - .withValues(mAfter) - .build(); - } else { - return ContentProviderOperation.newUpdate( - addCallerIsSyncAdapterParameter(Groups.CONTENT_URI)) - .withSelection(Groups._ID + "=" + this.getId(), null) - .withValues(mAfter) - .build(); - } - } else { - return null; - } - } - } - - private static Uri addCallerIsSyncAdapterParameter(Uri uri) { - return uri.buildUpon() - .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true") - .build(); - } - - /** - * {@link Comparator} to sort by {@link Groups#_ID}. - */ - private static Comparator<GroupDelta> sIdComparator = new Comparator<GroupDelta>() { - public int compare(GroupDelta object1, GroupDelta object2) { - final Long id1 = object1.getId(); - final Long id2 = object2.getId(); - if (id1 == null && id2 == null) { - return 0; - } else if (id1 == null) { - return -1; - } else if (id2 == null) { - return 1; - } else if (id1 < id2) { - return -1; - } else if (id1 > id2) { - return 1; - } else { - return 0; - } - } - }; - - /** - * Set of all {@link AccountDisplay} entries, one for each source. - */ - protected static class AccountSet extends ArrayList<AccountDisplay> { - public ArrayList<ContentProviderOperation> buildDiff() { - final ArrayList<ContentProviderOperation> diff = Lists.newArrayList(); - for (AccountDisplay account : this) { - account.buildDiff(diff); - } - return diff; - } - } - - /** - * {@link GroupDelta} details for a single {@link AccountWithDataSet}, usually shown as - * children under a single expandable group. - */ - protected static class AccountDisplay { - public final String mName; - public final String mType; - public final String mDataSet; - - public GroupDelta mUngrouped; - public ArrayList<GroupDelta> mSyncedGroups = Lists.newArrayList(); - public ArrayList<GroupDelta> mUnsyncedGroups = Lists.newArrayList(); - - /** - * Build an {@link AccountDisplay} covering all {@link Groups} under the - * given {@link AccountWithDataSet}. - */ - public AccountDisplay(ContentResolver resolver, String accountName, String accountType, - String dataSet) { - mName = accountName; - mType = accountType; - mDataSet = dataSet; - } - - /** - * Add the given {@link GroupDelta} internally, filing based on its - * {@link GroupDelta#getShouldSync()} status. - */ - private void addGroup(GroupDelta group) { - if (group.getShouldSync()) { - mSyncedGroups.add(group); - } else { - mUnsyncedGroups.add(group); - } - } - - /** - * Set the {@link GroupDelta#putShouldSync(boolean)} value for all - * children {@link GroupDelta} rows. - */ - public void setShouldSync(boolean shouldSync) { - final Iterator<GroupDelta> oppositeChildren = shouldSync ? - mUnsyncedGroups.iterator() : mSyncedGroups.iterator(); - while (oppositeChildren.hasNext()) { - final GroupDelta child = oppositeChildren.next(); - setShouldSync(child, shouldSync, false); - oppositeChildren.remove(); - } - } - - public void setShouldSync(GroupDelta child, boolean shouldSync) { - setShouldSync(child, shouldSync, true); - } - - /** - * Set {@link GroupDelta#putShouldSync(boolean)}, and file internally - * based on updated state. - */ - public void setShouldSync(GroupDelta child, boolean shouldSync, boolean attemptRemove) { - child.putShouldSync(shouldSync); - if (shouldSync) { - if (attemptRemove) { - mUnsyncedGroups.remove(child); - } - mSyncedGroups.add(child); - Collections.sort(mSyncedGroups, sIdComparator); - } else { - if (attemptRemove) { - mSyncedGroups.remove(child); - } - mUnsyncedGroups.add(child); - } - } - - /** - * Build set of {@link ContentProviderOperation} to persist any user - * changes to {@link GroupDelta} rows under this {@link AccountWithDataSet}. - */ - public void buildDiff(ArrayList<ContentProviderOperation> diff) { - for (GroupDelta group : mSyncedGroups) { - final ContentProviderOperation oper = group.buildDiff(); - if (oper != null) diff.add(oper); - } - for (GroupDelta group : mUnsyncedGroups) { - final ContentProviderOperation oper = group.buildDiff(); - if (oper != null) diff.add(oper); - } - } - } - - /** - * {@link ExpandableListAdapter} that shows {@link GroupDelta} settings, - * grouped by {@link AccountWithDataSet} type. Shows footer row when any groups are - * unsynced, as determined through {@link AccountDisplay#mUnsyncedGroups}. - */ - protected static class DisplayAdapter extends BaseExpandableListAdapter { - private Context mContext; - private LayoutInflater mInflater; - private AccountTypeManager mAccountTypes; - private AccountSet mAccounts; - - private boolean mChildWithPhones = false; - - public DisplayAdapter(Context context) { - mContext = context; - mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mAccountTypes = AccountTypeManager.getInstance(context); - } - - public void setAccounts(AccountSet accounts) { - mAccounts = accounts; - notifyDataSetChanged(); - } - - /** - * In group descriptions, show the number of contacts with phone - * numbers, in addition to the total contacts. - */ - public void setChildDescripWithPhones(boolean withPhones) { - mChildWithPhones = withPhones; - } - - @Override - public View getGroupView(int groupPosition, boolean isExpanded, View convertView, - ViewGroup parent) { - if (convertView == null) { - convertView = mInflater.inflate( - R.layout.custom_contact_list_filter_account, parent, false); - } - - final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1); - final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2); - - final AccountDisplay account = (AccountDisplay)this.getGroup(groupPosition); - - final AccountType accountType = mAccountTypes.getAccountType( - account.mType, account.mDataSet); - - text1.setText(account.mName); - text1.setVisibility(account.mName == null ? View.GONE : View.VISIBLE); - text2.setText(accountType.getDisplayLabel(mContext)); - - return convertView; - } - - @Override - public View getChildView(int groupPosition, int childPosition, boolean isLastChild, - View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = mInflater.inflate( - R.layout.custom_contact_list_filter_group, parent, false); - } - - final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1); - final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2); - final CheckBox checkbox = (CheckBox)convertView.findViewById(android.R.id.checkbox); - - final AccountDisplay account = mAccounts.get(groupPosition); - final GroupDelta child = (GroupDelta)this.getChild(groupPosition, childPosition); - if (child != null) { - // Handle normal group, with title and checkbox - final boolean groupVisible = child.getVisible(); - checkbox.setVisibility(View.VISIBLE); - checkbox.setChecked(groupVisible); - - final CharSequence groupTitle = child.getTitle(mContext); - text1.setText(groupTitle); - text2.setVisibility(View.GONE); - } else { - // When unknown child, this is "more" footer view - checkbox.setVisibility(View.GONE); - text1.setText(R.string.display_more_groups); - text2.setVisibility(View.GONE); - } - - return convertView; - } - - @Override - public Object getChild(int groupPosition, int childPosition) { - final AccountDisplay account = mAccounts.get(groupPosition); - final boolean validChild = childPosition >= 0 - && childPosition < account.mSyncedGroups.size(); - if (validChild) { - return account.mSyncedGroups.get(childPosition); - } else { - return null; - } - } - - @Override - public long getChildId(int groupPosition, int childPosition) { - final GroupDelta child = (GroupDelta)getChild(groupPosition, childPosition); - if (child != null) { - final Long childId = child.getId(); - return childId != null ? childId : Long.MIN_VALUE; - } else { - return Long.MIN_VALUE; - } - } - - @Override - public int getChildrenCount(int groupPosition) { - // Count is any synced groups, plus possible footer - final AccountDisplay account = mAccounts.get(groupPosition); - final boolean anyHidden = account.mUnsyncedGroups.size() > 0; - return account.mSyncedGroups.size() + (anyHidden ? 1 : 0); - } - - @Override - public Object getGroup(int groupPosition) { - return mAccounts.get(groupPosition); - } - - @Override - public int getGroupCount() { - if (mAccounts == null) { - return 0; - } - return mAccounts.size(); - } - - @Override - public long getGroupId(int groupPosition) { - return groupPosition; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public boolean isChildSelectable(int groupPosition, int childPosition) { - return true; - } - } - - /** {@inheritDoc} */ - public void onClick(View view) { - switch (view.getId()) { - case R.id.btn_done: { - this.doSaveAction(); - break; - } - case R.id.btn_discard: { - this.finish(); - break; - } - } - } - - /** - * Handle any clicks on {@link ExpandableListAdapter} children, which - * usually mean toggling its visible state. - */ - @Override - public boolean onChildClick(ExpandableListView parent, View view, int groupPosition, - int childPosition, long id) { - final CheckBox checkbox = (CheckBox)view.findViewById(android.R.id.checkbox); - - final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition); - final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition); - if (child != null) { - checkbox.toggle(); - child.putVisible(checkbox.isChecked()); - } else { - // Open context menu for bringing back unsynced - this.openContextMenu(view); - } - return true; - } - - // TODO: move these definitions to framework constants when we begin - // defining this mode through <sync-adapter> tags - private static final int SYNC_MODE_UNSUPPORTED = 0; - private static final int SYNC_MODE_UNGROUPED = 1; - private static final int SYNC_MODE_EVERYTHING = 2; - - protected int getSyncMode(AccountDisplay account) { - // TODO: read sync mode through <sync-adapter> definition - if (GoogleAccountType.ACCOUNT_TYPE.equals(account.mType) && account.mDataSet == null) { - return SYNC_MODE_EVERYTHING; - } else { - return SYNC_MODE_UNSUPPORTED; - } - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, - ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - // Bail if not working with expandable long-press, or if not child - if (!(menuInfo instanceof ExpandableListContextMenuInfo)) return; - - final ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo; - final int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition); - final int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition); - - // Skip long-press on expandable parents - if (childPosition == -1) return; - - final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition); - final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition); - - // Ignore when selective syncing unsupported - final int syncMode = getSyncMode(account); - if (syncMode == SYNC_MODE_UNSUPPORTED) return; - - if (child != null) { - showRemoveSync(menu, account, child, syncMode); - } else { - showAddSync(menu, account, syncMode); - } - } - - protected void showRemoveSync(ContextMenu menu, final AccountDisplay account, - final GroupDelta child, final int syncMode) { - final CharSequence title = child.getTitle(this); - - menu.setHeaderTitle(title); - menu.add(R.string.menu_sync_remove).setOnMenuItemClickListener( - new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - handleRemoveSync(account, child, syncMode, title); - return true; - } - }); - } - - protected void handleRemoveSync(final AccountDisplay account, final GroupDelta child, - final int syncMode, CharSequence title) { - final boolean shouldSyncUngrouped = account.mUngrouped.getShouldSync(); - if (syncMode == SYNC_MODE_EVERYTHING && shouldSyncUngrouped - && !child.equals(account.mUngrouped)) { - // Warn before removing this group when it would cause ungrouped to stop syncing - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - final CharSequence removeMessage = this.getString( - R.string.display_warn_remove_ungrouped, title); - builder.setTitle(R.string.menu_sync_remove); - builder.setMessage(removeMessage); - builder.setNegativeButton(android.R.string.cancel, null); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // Mark both this group and ungrouped to stop syncing - account.setShouldSync(account.mUngrouped, false); - account.setShouldSync(child, false); - mAdapter.notifyDataSetChanged(); - } - }); - builder.show(); - } else { - // Mark this group to not sync - account.setShouldSync(child, false); - mAdapter.notifyDataSetChanged(); - } - } - - protected void showAddSync(ContextMenu menu, final AccountDisplay account, final int syncMode) { - menu.setHeaderTitle(R.string.dialog_sync_add); - - // Create item for each available, unsynced group - for (final GroupDelta child : account.mUnsyncedGroups) { - if (!child.getShouldSync()) { - final CharSequence title = child.getTitle(this); - menu.add(title).setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // Adding specific group for syncing - if (child.mUngrouped && syncMode == SYNC_MODE_EVERYTHING) { - account.setShouldSync(true); - } else { - account.setShouldSync(child, true); - } - mAdapter.notifyDataSetChanged(); - return true; - } - }); - } - } - } - - @SuppressWarnings("unchecked") - private void doSaveAction() { - if (mAdapter == null || mAdapter.mAccounts == null) { - finish(); - return; - } - - setResult(RESULT_OK); - - final ArrayList<ContentProviderOperation> diff = mAdapter.mAccounts.buildDiff(); - if (diff.isEmpty()) { - finish(); - return; - } - - new UpdateTask(this).execute(diff); - } - - /** - * Background task that persists changes to {@link Groups#GROUP_VISIBLE}, - * showing spinner dialog to user while updating. - */ - public static class UpdateTask extends - WeakAsyncTask<ArrayList<ContentProviderOperation>, Void, Void, Activity> { - private ProgressDialog mProgress; - - public UpdateTask(Activity target) { - super(target); - } - - /** {@inheritDoc} */ - @Override - protected void onPreExecute(Activity target) { - final Context context = target; - - mProgress = ProgressDialog.show( - context, null, context.getText(R.string.savingDisplayGroups)); - - // Before starting this task, start an empty service to protect our - // process from being reclaimed by the system. - context.startService(new Intent(context, EmptyService.class)); - } - - /** {@inheritDoc} */ - @Override - protected Void doInBackground( - Activity target, ArrayList<ContentProviderOperation>... params) { - final Context context = target; - final ContentValues values = new ContentValues(); - final ContentResolver resolver = context.getContentResolver(); - - try { - final ArrayList<ContentProviderOperation> diff = params[0]; - resolver.applyBatch(ContactsContract.AUTHORITY, diff); - } catch (RemoteException e) { - Log.e(TAG, "Problem saving display groups", e); - } catch (OperationApplicationException e) { - Log.e(TAG, "Problem saving display groups", e); - } - - return null; - } - - /** {@inheritDoc} */ - @Override - protected void onPostExecute(Activity target, Void result) { - final Context context = target; - - try { - mProgress.dismiss(); - } catch (Exception e) { - Log.e(TAG, "Error dismissing progress dialog", e); - } - - target.finish(); - - // Stop the service that was protecting us - context.stopService(new Intent(context, EmptyService.class)); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - // Pretend cancel. - setResult(Activity.RESULT_CANCELED); - finish(); - return true; - default: - break; - } - return super.onOptionsItemSelected(item); - } -} diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java index 424a7b88f..30d5b36ac 100644 --- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java +++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java @@ -38,7 +38,7 @@ import com.android.contacts.common.list.ContactListFilterController; import com.android.contacts.common.list.DefaultContactListAdapter; import com.android.contacts.common.list.ProfileAndContactsLoader; import com.android.contacts.editor.ContactEditorFragment; -import com.android.contacts.util.AccountFilterUtil; +import com.android.contacts.common.util.AccountFilterUtil; /** * Fragment containing a contact list used for browsing (as compared to diff --git a/src/com/android/contacts/list/PhoneNumberPickerFragment.java b/src/com/android/contacts/list/PhoneNumberPickerFragment.java index 464afa379..3fc3135bd 100644 --- a/src/com/android/contacts/list/PhoneNumberPickerFragment.java +++ b/src/com/android/contacts/list/PhoneNumberPickerFragment.java @@ -34,8 +34,9 @@ import com.android.contacts.common.list.ContactListFilterController; import com.android.contacts.common.list.ContactListItemView; import com.android.contacts.common.list.DirectoryListLoader; import com.android.contacts.common.list.PhoneNumberListAdapter; -import com.android.contacts.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; -import com.android.contacts.util.AccountFilterUtil; +import com.android.contacts.common.list.ShortcutIntentBuilder; +import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; +import com.android.contacts.common.util.AccountFilterUtil; /** * Fragment containing a phone number list for picking. diff --git a/src/com/android/contacts/list/ShortcutIntentBuilder.java b/src/com/android/contacts/list/ShortcutIntentBuilder.java deleted file mode 100644 index 447328b75..000000000 --- a/src/com/android/contacts/list/ShortcutIntentBuilder.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.contacts.list; - -import android.app.ActivityManager; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Paint.FontMetricsInt; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.AsyncTask; -import android.provider.ContactsContract; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.CommonDataKinds.Photo; -import android.provider.ContactsContract.Contacts; -import android.provider.ContactsContract.Data; -import android.text.TextPaint; -import android.text.TextUtils; -import android.text.TextUtils.TruncateAt; - -import com.android.contacts.common.CallUtil; -import com.android.contacts.R; - -/** - * Constructs shortcut intents. - */ -public class ShortcutIntentBuilder { - - private static final String[] CONTACT_COLUMNS = { - Contacts.DISPLAY_NAME, - Contacts.PHOTO_ID, - }; - - private static final int CONTACT_DISPLAY_NAME_COLUMN_INDEX = 0; - private static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 1; - - private static final String[] PHONE_COLUMNS = { - Phone.DISPLAY_NAME, - Phone.PHOTO_ID, - Phone.NUMBER, - Phone.TYPE, - Phone.LABEL - }; - - private static final int PHONE_DISPLAY_NAME_COLUMN_INDEX = 0; - private static final int PHONE_PHOTO_ID_COLUMN_INDEX = 1; - private static final int PHONE_NUMBER_COLUMN_INDEX = 2; - private static final int PHONE_TYPE_COLUMN_INDEX = 3; - private static final int PHONE_LABEL_COLUMN_INDEX = 4; - - private static final String[] PHOTO_COLUMNS = { - Photo.PHOTO, - }; - - private static final int PHOTO_PHOTO_COLUMN_INDEX = 0; - - private static final String PHOTO_SELECTION = Photo._ID + "=?"; - - private final OnShortcutIntentCreatedListener mListener; - private final Context mContext; - private int mIconSize; - private final int mIconDensity; - private final int mBorderWidth; - private final int mBorderColor; - - /** - * This is a hidden API of the launcher in JellyBean that allows us to disable the animation - * that it would usually do, because it interferes with our own animation for QuickContact - */ - public static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION = - "com.android.launcher.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION"; - - /** - * Listener interface. - */ - public interface OnShortcutIntentCreatedListener { - - /** - * Callback for shortcut intent creation. - * - * @param uri the original URI for which the shortcut intent has been - * created. - * @param shortcutIntent resulting shortcut intent. - */ - void onShortcutIntentCreated(Uri uri, Intent shortcutIntent); - } - - public ShortcutIntentBuilder(Context context, OnShortcutIntentCreatedListener listener) { - mContext = context; - mListener = listener; - - final Resources r = context.getResources(); - final ActivityManager am = (ActivityManager) context - .getSystemService(Context.ACTIVITY_SERVICE); - mIconSize = r.getDimensionPixelSize(R.dimen.shortcut_icon_size); - if (mIconSize == 0) { - mIconSize = am.getLauncherLargeIconSize(); - } - mIconDensity = am.getLauncherLargeIconDensity(); - mBorderWidth = r.getDimensionPixelOffset( - R.dimen.shortcut_icon_border_width); - mBorderColor = r.getColor(R.color.shortcut_overlay_text_background); - } - - public void createContactShortcutIntent(Uri contactUri) { - new ContactLoadingAsyncTask(contactUri).execute(); - } - - public void createPhoneNumberShortcutIntent(Uri dataUri, String shortcutAction) { - new PhoneNumberLoadingAsyncTask(dataUri, shortcutAction).execute(); - } - - /** - * An asynchronous task that loads name, photo and other data from the database. - */ - private abstract class LoadingAsyncTask extends AsyncTask<Void, Void, Void> { - protected Uri mUri; - protected String mContentType; - protected String mDisplayName; - protected byte[] mBitmapData; - protected long mPhotoId; - - public LoadingAsyncTask(Uri uri) { - mUri = uri; - } - - @Override - protected Void doInBackground(Void... params) { - mContentType = mContext.getContentResolver().getType(mUri); - loadData(); - loadPhoto(); - return null; - } - - protected abstract void loadData(); - - private void loadPhoto() { - if (mPhotoId == 0) { - return; - } - - ContentResolver resolver = mContext.getContentResolver(); - Cursor cursor = resolver.query(Data.CONTENT_URI, PHOTO_COLUMNS, PHOTO_SELECTION, - new String[] { String.valueOf(mPhotoId) }, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - mBitmapData = cursor.getBlob(PHOTO_PHOTO_COLUMN_INDEX); - } - } finally { - cursor.close(); - } - } - } - } - - private final class ContactLoadingAsyncTask extends LoadingAsyncTask { - public ContactLoadingAsyncTask(Uri uri) { - super(uri); - } - - @Override - protected void loadData() { - ContentResolver resolver = mContext.getContentResolver(); - Cursor cursor = resolver.query(mUri, CONTACT_COLUMNS, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - mDisplayName = cursor.getString(CONTACT_DISPLAY_NAME_COLUMN_INDEX); - mPhotoId = cursor.getLong(CONTACT_PHOTO_ID_COLUMN_INDEX); - } - } finally { - cursor.close(); - } - } - } - @Override - protected void onPostExecute(Void result) { - createContactShortcutIntent(mUri, mContentType, mDisplayName, mBitmapData); - } - } - - private final class PhoneNumberLoadingAsyncTask extends LoadingAsyncTask { - private final String mShortcutAction; - private String mPhoneNumber; - private int mPhoneType; - private String mPhoneLabel; - - public PhoneNumberLoadingAsyncTask(Uri uri, String shortcutAction) { - super(uri); - mShortcutAction = shortcutAction; - } - - @Override - protected void loadData() { - ContentResolver resolver = mContext.getContentResolver(); - Cursor cursor = resolver.query(mUri, PHONE_COLUMNS, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - mDisplayName = cursor.getString(PHONE_DISPLAY_NAME_COLUMN_INDEX); - mPhotoId = cursor.getLong(PHONE_PHOTO_ID_COLUMN_INDEX); - mPhoneNumber = cursor.getString(PHONE_NUMBER_COLUMN_INDEX); - mPhoneType = cursor.getInt(PHONE_TYPE_COLUMN_INDEX); - mPhoneLabel = cursor.getString(PHONE_LABEL_COLUMN_INDEX); - } - } finally { - cursor.close(); - } - } - } - - @Override - protected void onPostExecute(Void result) { - createPhoneNumberShortcutIntent(mUri, mDisplayName, mBitmapData, mPhoneNumber, - mPhoneType, mPhoneLabel, mShortcutAction); - } - } - - private Bitmap getPhotoBitmap(byte[] bitmapData) { - Bitmap bitmap; - if (bitmapData != null) { - bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length, null); - } else { - bitmap = ((BitmapDrawable) mContext.getResources().getDrawableForDensity( - R.drawable.ic_contact_picture_holo_light, mIconDensity)).getBitmap(); - } - return bitmap; - } - - private void createContactShortcutIntent(Uri contactUri, String contentType, String displayName, - byte[] bitmapData) { - Bitmap bitmap = getPhotoBitmap(bitmapData); - - Intent shortcutIntent = new Intent(ContactsContract.QuickContact.ACTION_QUICK_CONTACT); - - // When starting from the launcher, start in a new, cleared task. - // CLEAR_WHEN_TASK_RESET cannot reset the root of a task, so we - // clear the whole thing preemptively here since QuickContactActivity will - // finish itself when launching other detail activities. - shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - - // Tell the launcher to not do its animation, because we are doing our own - shortcutIntent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true); - - shortcutIntent.setDataAndType(contactUri, contentType); - shortcutIntent.putExtra(ContactsContract.QuickContact.EXTRA_MODE, - ContactsContract.QuickContact.MODE_LARGE); - shortcutIntent.putExtra(ContactsContract.QuickContact.EXTRA_EXCLUDE_MIMES, - (String[]) null); - - final Bitmap icon = generateQuickContactIcon(bitmap); - - Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - if (TextUtils.isEmpty(displayName)) { - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, mContext.getResources().getString( - R.string.missing_name)); - } else { - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, displayName); - } - - mListener.onShortcutIntentCreated(contactUri, intent); - } - - private void createPhoneNumberShortcutIntent(Uri uri, String displayName, byte[] bitmapData, - String phoneNumber, int phoneType, String phoneLabel, String shortcutAction) { - Bitmap bitmap = getPhotoBitmap(bitmapData); - - Uri phoneUri; - if (Intent.ACTION_CALL.equals(shortcutAction)) { - // Make the URI a direct tel: URI so that it will always continue to work - phoneUri = Uri.fromParts(CallUtil.SCHEME_TEL, phoneNumber, null); - bitmap = generatePhoneNumberIcon(bitmap, phoneType, phoneLabel, - R.drawable.badge_action_call); - } else { - phoneUri = Uri.fromParts(CallUtil.SCHEME_SMSTO, phoneNumber, null); - bitmap = generatePhoneNumberIcon(bitmap, phoneType, phoneLabel, - R.drawable.badge_action_sms); - } - - Intent shortcutIntent = new Intent(shortcutAction, phoneUri); - shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - - Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, displayName); - - mListener.onShortcutIntentCreated(uri, intent); - } - - private void drawBorder(Canvas canvas, Rect dst) { - // Darken the border - final Paint workPaint = new Paint(); - workPaint.setColor(mBorderColor); - workPaint.setStyle(Paint.Style.STROKE); - // The stroke is drawn centered on the rect bounds, and since half will be drawn outside the - // bounds, we need to double the width for it to appear as intended. - workPaint.setStrokeWidth(mBorderWidth * 2); - canvas.drawRect(dst, workPaint); - } - - private Bitmap generateQuickContactIcon(Bitmap photo) { - - // Setup the drawing classes - Bitmap icon = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(icon); - - // Copy in the photo - Paint photoPaint = new Paint(); - photoPaint.setDither(true); - photoPaint.setFilterBitmap(true); - Rect src = new Rect(0,0, photo.getWidth(),photo.getHeight()); - Rect dst = new Rect(0,0, mIconSize, mIconSize); - canvas.drawBitmap(photo, src, dst, photoPaint); - - drawBorder(canvas, dst); - - Drawable overlay = mContext.getResources().getDrawableForDensity( - com.android.internal.R.drawable.quickcontact_badge_overlay_dark, mIconDensity); - - overlay.setBounds(dst); - overlay.draw(canvas); - canvas.setBitmap(null); - - return icon; - } - - /** - * Generates a phone number shortcut icon. Adds an overlay describing the type of the phone - * number, and if there is a photo also adds the call action icon. - */ - private Bitmap generatePhoneNumberIcon(Bitmap photo, int phoneType, String phoneLabel, - int actionResId) { - final Resources r = mContext.getResources(); - final float density = r.getDisplayMetrics().density; - - Bitmap phoneIcon = ((BitmapDrawable) r.getDrawableForDensity(actionResId, mIconDensity)) - .getBitmap(); - - // Setup the drawing classes - Bitmap icon = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(icon); - - // Copy in the photo - Paint photoPaint = new Paint(); - photoPaint.setDither(true); - photoPaint.setFilterBitmap(true); - Rect src = new Rect(0, 0, photo.getWidth(), photo.getHeight()); - Rect dst = new Rect(0, 0, mIconSize, mIconSize); - canvas.drawBitmap(photo, src, dst, photoPaint); - - drawBorder(canvas, dst); - - // Create an overlay for the phone number type - CharSequence overlay = Phone.getTypeLabel(r, phoneType, phoneLabel); - - if (overlay != null) { - TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); - textPaint.setTextSize(r.getDimension(R.dimen.shortcut_overlay_text_size)); - textPaint.setColor(r.getColor(R.color.textColorIconOverlay)); - textPaint.setShadowLayer(4f, 0, 2f, r.getColor(R.color.textColorIconOverlayShadow)); - - final FontMetricsInt fmi = textPaint.getFontMetricsInt(); - - // First fill in a darker background around the text to be drawn - final Paint workPaint = new Paint(); - workPaint.setColor(mBorderColor); - workPaint.setStyle(Paint.Style.FILL); - final int textPadding = r - .getDimensionPixelOffset(R.dimen.shortcut_overlay_text_background_padding); - final int textBandHeight = (fmi.descent - fmi.ascent) + textPadding * 2; - dst.set(0 + mBorderWidth, mIconSize - textBandHeight, mIconSize - mBorderWidth, - mIconSize - mBorderWidth); - canvas.drawRect(dst, workPaint); - - final float sidePadding = mBorderWidth; - overlay = TextUtils.ellipsize(overlay, textPaint, mIconSize - 2 * sidePadding, - TruncateAt.END_SMALL); - final float textWidth = textPaint.measureText(overlay, 0, overlay.length()); - canvas.drawText(overlay, 0, overlay.length(), (mIconSize - textWidth) / 2, mIconSize - - fmi.descent - textPadding, textPaint); - } - - // Draw the phone action icon as an overlay - src.set(0, 0, phoneIcon.getWidth(), phoneIcon.getHeight()); - int iconWidth = icon.getWidth(); - dst.set(iconWidth - ((int) (20 * density)), -1, - iconWidth, ((int) (19 * density))); - dst.offset(-mBorderWidth, mBorderWidth); - canvas.drawBitmap(phoneIcon, src, dst, photoPaint); - - canvas.setBitmap(null); - - return icon; - } -} diff --git a/src/com/android/contacts/util/AccountFilterUtil.java b/src/com/android/contacts/util/AccountFilterUtil.java deleted file mode 100644 index 1540d04d7..000000000 --- a/src/com/android/contacts/util/AccountFilterUtil.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.contacts.util; - -import android.app.Activity; -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; -import android.util.Log; -import android.view.View; -import android.widget.TextView; - -import com.android.contacts.R; -import com.android.contacts.list.AccountFilterActivity; -import com.android.contacts.common.list.ContactListFilter; -import com.android.contacts.common.list.ContactListFilterController; - -/** - * Utility class for account filter manipulation. - */ -public class AccountFilterUtil { - private static final String TAG = AccountFilterUtil.class.getSimpleName(); - - /** - * Find TextView with the id "account_filter_header" and set correct text for the account - * filter header. - * - * @param filterContainer View containing TextView with id "account_filter_header" - * @return true when header text is set in the call. You may use this for conditionally - * showing or hiding this entire view. - */ - public static boolean updateAccountFilterTitleForPeople(View filterContainer, - ContactListFilter filter, boolean showTitleForAllAccounts) { - return updateAccountFilterTitle(filterContainer, filter, showTitleForAllAccounts, false); - } - - /** - * Similar to {@link #updateAccountFilterTitleForPeople(View, ContactListFilter, boolean, - * boolean)}, but for Phone UI. - */ - public static boolean updateAccountFilterTitleForPhone(View filterContainer, - ContactListFilter filter, boolean showTitleForAllAccounts) { - return updateAccountFilterTitle( - filterContainer, filter, showTitleForAllAccounts, true); - } - - private static boolean updateAccountFilterTitle(View filterContainer, - ContactListFilter filter, boolean showTitleForAllAccounts, - boolean forPhone) { - final Context context = filterContainer.getContext(); - final TextView headerTextView = (TextView) - filterContainer.findViewById(R.id.account_filter_header); - - boolean textWasSet = false; - if (filter != null) { - if (forPhone) { - if (filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) { - if (showTitleForAllAccounts) { - headerTextView.setText(R.string.list_filter_phones); - textWasSet = true; - } - } else if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT) { - headerTextView.setText(context.getString( - R.string.listAllContactsInAccount, filter.accountName)); - textWasSet = true; - } else if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) { - headerTextView.setText(R.string.listCustomView); - textWasSet = true; - } else { - Log.w(TAG, "Filter type \"" + filter.filterType + "\" isn't expected."); - } - } else { - if (filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) { - if (showTitleForAllAccounts) { - headerTextView.setText(R.string.list_filter_all_accounts); - textWasSet = true; - } - } else if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT) { - headerTextView.setText(context.getString( - R.string.listAllContactsInAccount, filter.accountName)); - textWasSet = true; - } else if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) { - headerTextView.setText(R.string.listCustomView); - textWasSet = true; - } else if (filter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) { - headerTextView.setText(R.string.listSingleContact); - textWasSet = true; - } else { - Log.w(TAG, "Filter type \"" + filter.filterType + "\" isn't expected."); - } - } - } else { - Log.w(TAG, "Filter is null."); - } - return textWasSet; - } - - /** - * Launches account filter setting Activity using - * {@link Activity#startActivityForResult(Intent, int)}. - * - * @param activity - * @param requestCode requestCode for {@link Activity#startActivityForResult(Intent, int)} - * @param currentFilter currently-selected filter, so that it can be displayed as activated. - */ - public static void startAccountFilterActivityForResult( - Activity activity, int requestCode, ContactListFilter currentFilter) { - final Intent intent = new Intent(activity, AccountFilterActivity.class); - intent.putExtra(AccountFilterActivity.KEY_EXTRA_CURRENT_FILTER, currentFilter); - activity.startActivityForResult(intent, requestCode); - } - - /** - * Very similar to - * {@link #startAccountFilterActivityForResult(Activity, int, ContactListFilter)} - * but uses Fragment instead. - */ - public static void startAccountFilterActivityForResult( - Fragment fragment, int requestCode, ContactListFilter currentFilter) { - final Activity activity = fragment.getActivity(); - if (activity != null) { - final Intent intent = new Intent(activity, AccountFilterActivity.class); - intent.putExtra(AccountFilterActivity.KEY_EXTRA_CURRENT_FILTER, currentFilter); - fragment.startActivityForResult(intent, requestCode); - } else { - Log.w(TAG, "getActivity() returned null. Ignored"); - } - } - - /** - * Useful method to handle onActivityResult() for - * {@link #startAccountFilterActivityForResult(Activity, int)} or - * {@link #startAccountFilterActivityForResult(Fragment, int)}. - * - * This will update filter via a given ContactListFilterController. - */ - public static void handleAccountFilterResult( - ContactListFilterController filterController, int resultCode, Intent data) { - if (resultCode == Activity.RESULT_OK) { - final ContactListFilter filter = (ContactListFilter) - data.getParcelableExtra(AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER); - if (filter == null) { - return; - } - if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) { - filterController.selectCustomFilter(); - } else { - filterController.setContactListFilter(filter, true); - } - } - } -} diff --git a/src/com/android/contacts/util/EmptyService.java b/src/com/android/contacts/util/EmptyService.java deleted file mode 100644 index 2e6a159bf..000000000 --- a/src/com/android/contacts/util/EmptyService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.contacts.util; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -/** - * Background {@link Service} that is used to keep our process alive long enough - * for background threads to finish. Started and stopped directly by specific - * background tasks when needed. - */ -public class EmptyService extends Service { - @Override - public IBinder onBind(Intent intent) { - return null; - } -} diff --git a/src/com/android/contacts/util/LocalizedNameResolver.java b/src/com/android/contacts/util/LocalizedNameResolver.java deleted file mode 100644 index ec0b8124b..000000000 --- a/src/com/android/contacts/util/LocalizedNameResolver.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.contacts.util; - -import android.accounts.AccountManager; -import android.accounts.AuthenticatorDescription; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ServiceInfo; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Xml; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; - -/** - * Retrieves localized names per account type. This allows customizing texts like - * "All Contacts" for certain account types, but e.g. "All Friends" or "All Connections" for others. - */ -public class LocalizedNameResolver { - private static final String TAG = "LocalizedNameResolver"; - - /** - * Meta-data key for the contacts configuration associated with a sync service. - */ - private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE"; - - private static final String CONTACTS_DATA_KIND = "ContactsDataKind"; - - /** - * Returns the name for All Contacts for the specified account type. - */ - public static String getAllContactsName(Context context, String accountType) { - if (context == null) throw new IllegalArgumentException("Context must not be null"); - if (accountType == null) return null; - - return resolveAllContactsName(context, accountType); - } - - /** - * Finds "All Contacts"-Name for the specified account type. - */ - private static String resolveAllContactsName(Context context, String accountType) { - final AccountManager am = AccountManager.get(context); - - for (AuthenticatorDescription auth : am.getAuthenticatorTypes()) { - if (accountType.equals(auth.type)) { - return resolveAllContactsNameFromMetaData(context, auth.packageName); - } - } - - return null; - } - - /** - * Finds the meta-data XML containing the contacts configuration and - * reads the picture priority from that file. - */ - private static String resolveAllContactsNameFromMetaData(Context context, String packageName) { - final PackageManager pm = context.getPackageManager(); - try { - PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SERVICES - | PackageManager.GET_META_DATA); - if (pi != null && pi.services != null) { - for (ServiceInfo si : pi.services) { - final XmlResourceParser parser = si.loadXmlMetaData(pm, METADATA_CONTACTS); - if (parser != null) { - return loadAllContactsNameFromXml(context, parser, packageName); - } - } - } - } catch (NameNotFoundException e) { - Log.w(TAG, "Problem loading \"All Contacts\"-name: " + e.toString()); - } - return null; - } - - private static String loadAllContactsNameFromXml(Context context, XmlPullParser parser, - String packageName) { - try { - final AttributeSet attrs = Xml.asAttributeSet(parser); - int type; - while ((type = parser.next()) != XmlPullParser.START_TAG - && type != XmlPullParser.END_DOCUMENT) { - // Drain comments and whitespace - } - - if (type != XmlPullParser.START_TAG) { - throw new IllegalStateException("No start tag found"); - } - - final int depth = parser.getDepth(); - while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && type != XmlPullParser.END_DOCUMENT) { - String name = parser.getName(); - if (type == XmlPullParser.START_TAG && CONTACTS_DATA_KIND.equals(name)) { - final TypedArray typedArray = context.obtainStyledAttributes(attrs, - android.R.styleable.ContactsDataKind); - try { - // See if a string has been hardcoded directly into the xml - final String nonResourceString = typedArray.getNonResourceString( - android.R.styleable.ContactsDataKind_allContactsName); - if (nonResourceString != null) { - return nonResourceString; - } - - // See if a resource is referenced. We can't rely on getString - // to automatically resolve it as the resource lives in a different package - int id = typedArray.getResourceId( - android.R.styleable.ContactsDataKind_allContactsName, 0); - if (id == 0) return null; - - // Resolve the resource Id - final PackageManager packageManager = context.getPackageManager(); - final Resources resources; - try { - resources = packageManager.getResourcesForApplication(packageName); - } catch (NameNotFoundException e) { - return null; - } - try { - return resources.getString(id); - } catch (NotFoundException e) { - return null; - } - } finally { - typedArray.recycle(); - } - } - } - return null; - } catch (XmlPullParserException e) { - throw new IllegalStateException("Problem reading XML", e); - } catch (IOException e) { - throw new IllegalStateException("Problem reading XML", e); - } - } -} diff --git a/src/com/android/contacts/util/WeakAsyncTask.java b/src/com/android/contacts/util/WeakAsyncTask.java deleted file mode 100644 index f60cfd781..000000000 --- a/src/com/android/contacts/util/WeakAsyncTask.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.contacts.util; - -import android.os.AsyncTask; - -import java.lang.ref.WeakReference; - -public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends - AsyncTask<Params, Progress, Result> { - protected WeakReference<WeakTarget> mTarget; - - public WeakAsyncTask(WeakTarget target) { - mTarget = new WeakReference<WeakTarget>(target); - } - - /** {@inheritDoc} */ - @Override - protected final void onPreExecute() { - final WeakTarget target = mTarget.get(); - if (target != null) { - this.onPreExecute(target); - } - } - - /** {@inheritDoc} */ - @Override - protected final Result doInBackground(Params... params) { - final WeakTarget target = mTarget.get(); - if (target != null) { - return this.doInBackground(target, params); - } else { - return null; - } - } - - /** {@inheritDoc} */ - @Override - protected final void onPostExecute(Result result) { - final WeakTarget target = mTarget.get(); - if (target != null) { - this.onPostExecute(target, result); - } - } - - protected void onPreExecute(WeakTarget target) { - // No default action - } - - protected abstract Result doInBackground(WeakTarget target, Params... params); - - protected void onPostExecute(WeakTarget target, Result result) { - // No default action - } -} |