Merge "Fix overdraw in PeopleActivity"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b791d94..eff52d8 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 -->
@@ -418,7 +418,6 @@
<!-- vCard related -->
<activity android:name=".vcard.ImportVCardActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
- android:screenOrientation="nosensor"
android:theme="@style/BackgroundOnlyTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
diff --git a/res/drawable-hdpi/badge_action_call.png b/res/drawable-hdpi/badge_action_call.png
deleted file mode 100644
index 0b1c6b4..0000000
--- a/res/drawable-hdpi/badge_action_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/badge_action_sms.png b/res/drawable-hdpi/badge_action_sms.png
deleted file mode 100644
index 0dfdbf5..0000000
--- a/res/drawable-hdpi/badge_action_sms.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_settings_holo_light.png b/res/drawable-hdpi/ic_menu_settings_holo_light.png
deleted file mode 100644
index b7bb5c4..0000000
--- a/res/drawable-hdpi/ic_menu_settings_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_star_holo_light.png b/res/drawable-hdpi/ic_menu_star_holo_light.png
deleted file mode 100644
index 4513796..0000000
--- a/res/drawable-hdpi/ic_menu_star_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/unknown_source.png b/res/drawable-hdpi/unknown_source.png
deleted file mode 100644
index 0a8f37d..0000000
--- a/res/drawable-hdpi/unknown_source.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/badge_action_call.png b/res/drawable-mdpi/badge_action_call.png
deleted file mode 100644
index af2abaa..0000000
--- a/res/drawable-mdpi/badge_action_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/badge_action_sms.png b/res/drawable-mdpi/badge_action_sms.png
deleted file mode 100644
index 13dd8bc..0000000
--- a/res/drawable-mdpi/badge_action_sms.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_settings_holo_light.png b/res/drawable-mdpi/ic_menu_settings_holo_light.png
deleted file mode 100644
index 1ebc112..0000000
--- a/res/drawable-mdpi/ic_menu_settings_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_star_holo_light.png b/res/drawable-mdpi/ic_menu_star_holo_light.png
deleted file mode 100644
index 8263b27..0000000
--- a/res/drawable-mdpi/ic_menu_star_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/unknown_source.png b/res/drawable-mdpi/unknown_source.png
deleted file mode 100644
index 356748f..0000000
--- a/res/drawable-mdpi/unknown_source.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/badge_action_call.png b/res/drawable-xhdpi/badge_action_call.png
deleted file mode 100644
index 2589e33..0000000
--- a/res/drawable-xhdpi/badge_action_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/badge_action_sms.png b/res/drawable-xhdpi/badge_action_sms.png
deleted file mode 100644
index 460451f..0000000
--- a/res/drawable-xhdpi/badge_action_sms.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_settings_holo_light.png b/res/drawable-xhdpi/ic_menu_settings_holo_light.png
deleted file mode 100644
index 68ba92b..0000000
--- a/res/drawable-xhdpi/ic_menu_settings_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_star_holo_light.png b/res/drawable-xhdpi/ic_menu_star_holo_light.png
deleted file mode 100644
index 9067911..0000000
--- a/res/drawable-xhdpi/ic_menu_star_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/unknown_source.png b/res/drawable-xhdpi/unknown_source.png
deleted file mode 100644
index 35e8fb4..0000000
--- a/res/drawable-xhdpi/unknown_source.png
+++ /dev/null
Binary files differ
diff --git a/res/layout/account_filter_header.xml b/res/layout/account_filter_header.xml
deleted file mode 100644
index 0ffb7e1..0000000
--- 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 362209c..0000000
--- 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 37aaf53..0000000
--- 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 40d9c78..0000000
--- 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 7814565..0000000
--- 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 8c1b6c1..0000000
--- 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 65ef405..0000000
--- 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 2625a43..0000000
--- 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-ko/strings.xml b/res/values-ko/strings.xml
index 0d64a04..51a70fd 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -286,7 +286,7 @@
<string name="display_options_view_given_name_first" msgid="6968288511197363292">"이름 먼저 표시"</string>
<string name="display_options_view_family_name_first" msgid="1447288164951453714">"성 먼저 표시"</string>
<string name="take_photo" msgid="7496128293167402354">"사진 찍기"</string>
- <string name="take_new_photo" msgid="7341354729436576304">"새 사진 가져오기"</string>
+ <string name="take_new_photo" msgid="7341354729436576304">"새 사진 찍기"</string>
<string name="pick_photo" msgid="3746334626214970837">"갤러리에서 사진 선택"</string>
<string name="pick_new_photo" msgid="7962368009197147617">"갤러리에서 새 사진 선택"</string>
<string name="locale_change_in_progress" msgid="7583992153091537467">"변경된 언어를 반영하도록 주소록을 업데이트하는 중입니다. 잠시 기다려 주세요."</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index c25610a..d13000f 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -139,13 +139,13 @@
<string name="simContacts_title" msgid="27341688347689769">"Kontakter från SIM-kort"</string>
<string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"Du har inga kontakter att visa. (Om du nyss lade till ett konto kan det ta några minuter innan kontakterna synkroniserats.)"</string>
<string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"Du har inga kontakter att visa."</string>
- <string name="noContactsHelpText" product="tablet" msgid="6226271923423236696">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som du kan synkronisera med pekdatorn"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SIM- eller SD-kortet"\n</li></string>
+ <string name="noContactsHelpText" product="tablet" msgid="6226271923423236696">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som du kan synkronisera med surfplattan"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SIM- eller SD-kortet"\n</li></string>
<string name="noContactsHelpText" product="default" msgid="4405064135698982080">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som du kan synkronisera med mobilen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SIM- eller SD-kortet"\n</li></string>
<string name="noContactsHelpTextWithSync" product="tablet" msgid="6773195806404659174">"Det finns inga kontakter att visa (Om du nyss har lagt till ett konto kan det ta några minuter att synkronisera kontakterna.)"\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras med pekdatorn"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativ"</b></font>" om du vill ändra vilka kontakter som är synliga"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SIM- eller SD-kortet"\n</li></string>
<string name="noContactsHelpTextWithSync" product="default" msgid="7016825676090327312">"Det finns inga kontakter att visa (Om du nyss har lagt till ett konto kan det ta några minuter att synkronisera kontakterna.)"\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras med mobilen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativ"</b></font>" om du vill ändra vilka kontakter som är synliga"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SIM- eller SD-kortet"\n</li></string>
- <string name="noContactsNoSimHelpText" product="tablet" msgid="7823757505923033456">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som du kan synkronisera med pekdatorn"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SD-kortet"\n</li></string>
+ <string name="noContactsNoSimHelpText" product="tablet" msgid="7823757505923033456">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som du kan synkronisera med surfplattan"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SD-kortet"\n</li></string>
<string name="noContactsNoSimHelpText" product="default" msgid="6224952277619986841">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som du kan synkronisera med mobilen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SD-kortet"\n</li></string>
- <string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="5415762667445638265">"Det finns inga kontakter att visa. (Om du nyss har lagt till ett konto kan det ta några minuter att synkronisera kontakterna.)"\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras med pekdatorn"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativ"</b></font>" om du vill ändra vilka kontakter som är synliga"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>"om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SD-kortet"\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="5415762667445638265">"Det finns inga kontakter att visa. (Om du nyss har lagt till ett konto kan det ta några minuter att synkronisera kontakterna.)"\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras med surfplattan"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativ"</b></font>" om du vill ändra vilka kontakter som är synliga"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>"om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SD-kortet"\n</li></string>
<string name="noContactsNoSimHelpTextWithSync" product="default" msgid="7443705129830284440">"Det finns inga kontakter att visa. (Om du nyss har lagt till ett konto kan det ta några minuter att synkronisera kontakterna.)"\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras med mobilen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativ"</b></font>" om du vill ändra vilka kontakter som är synliga"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>" om du vill importera kontakter från SD-kortet"\n</li></string>
<string name="noFavoritesHelpText" msgid="3744655776704833277">"Du har inte några favoriter."\n\n"Så här lägger du till kontakter i favoritlistan:"\n\n" "<li>"Tryck på fliken "<b>"Kontakter"</b>\n</li>" "\n<li>"Tryck på den kontakt du vill lägga till i favoriterna"\n</li>" "\n<li>"Tryck på stjärnan bredvid kontaktens namn"\n</li></string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Använda tonvalstelefon"</string>
diff --git a/res/values-sw580dp/dimens.xml b/res/values-sw580dp/dimens.xml
index d3a9bea..4c4505c 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 1181d5d..ce0ec15 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 9f8ce83..d7845c4 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 7a99cc3..99e917b 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 d22bf64..aaad313 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 4a84751..aadd05c 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>
@@ -246,12 +240,6 @@
<!-- The text displayed when the groups list is empty and no accounts are set on the device while displaying all groups [CHAR LIMIT=NONE] -->
<string name="noAccounts">To create groups you need an account.</string>
- <!-- The text displayed when the contacts list is empty while displaying results after searching contacts -->
- <string name="noMatchingContacts">No matching contacts found.</string>
-
- <!-- The text displayed when the contacts list is empty while displaying only contacts that have phone numbers -->
- <string name="noContactsWithPhoneNumbers">No contacts with phone numbers.</string>
-
<!-- The text displayed when there are no members in the group while displaying the group detail page [CHAR LIMIT=40] -->
<string name="emptyGroup">No people in this group.</string>
@@ -261,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>
@@ -303,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>
@@ -386,75 +362,6 @@
<!-- Dialog title displayed when loading a phone number from the SIM card for speed dial -->
<string name="simContacts_title">SIM card contacts</string>
- <!-- Displayed full screen when the user want to create a shortcut, but there is no contacts, and contact syncing is enabled -->
- <string name="noContactsHelpTextWithSyncForCreateShortcut">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)"</string>
-
- <!-- Displayed full screen when the user want to create a shortcut, but there is no contacts -->
- <string name="noContactsHelpTextForCreateShortcut">"You don't have any contacts to display."</string>
-
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is disabled. [CHAR LIMIT=NONE] -->
- <string name="noContactsHelpText" product="tablet">"You don't have any contacts to display.\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the tablet\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/export</b></font> to import contacts from your SIM or SD card\n</li>"
- </string>
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is disabled. [CHAR LIMIT=NONE] -->
- <string name="noContactsHelpText" product="default">"You don't have any contacts to display.\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the phone\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font> to import contacts from your SIM or SD card\n</li>"
- </string>
-
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled. [CHAR LIMIT=NONE] -->
- <string name="noContactsHelpTextWithSync" product="tablet">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the tablet\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font> to import contacts from your SIM or SD card\n</li>"
- </string>
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled. [CHAR LIMIT=NONE] -->
- <string name="noContactsHelpTextWithSync" product="default">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the phone\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font> to import contacts from your SIM or SD card\n</li>"
- </string>
-
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is disabled, and there is no sim card (cdma). [CHAR LIMIT=NONE]-->
- <string name="noContactsNoSimHelpText" product="tablet">"You don't have any contacts to display.\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the tablet\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font> to import contacts from your SD card\n</li>"
- </string>
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is disabled, and there is no sim card (cdma). [CHAR LIMIT=NONE]-->
- <string name="noContactsNoSimHelpText" product="default">"You don't have any contacts to display.\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the phone\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font> to import contacts from your SD card\n</li>"
- </string>
-
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled, and there is no sim card (cdma). [CHAR LIMIT=NONE] -->
- <string name="noContactsNoSimHelpTextWithSync" product="tablet">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the tablet\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font> to import contacts from your SD card\n</li>"
- </string>
- <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled, and there is no sim card (cdma). [CHAR LIMIT=NONE] -->
- <string name="noContactsNoSimHelpTextWithSync" product="default">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, touch <font fgcolor="#ffffffff"><b>Menu</b></font>, then touch:\n
- \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or set up an account with contacts you can sync to the phone\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
- \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font> to import contacts from your SD card\n</li>"
- </string>
-
- <!-- Displayed full screen when the user has no favorites and they are displaying the favorites tab. [CHAR LIMIT=NONE] -->
- <string name="noFavoritesHelpText">"You don't have any favorites.\n\nTo add a contact to your list of favorites:\n
- <li>Touch the <b>Contacts</b> tab\n</li>
- \n<li>Touch the contact you want to add to your favorites\n</li>
- \n<li>Touch the star next to the contact\'s name\n</li>"
- </string>
-
<!-- Item label: jump to the in-call DTMF dialpad.
(Part of a list of options shown in the dialer when another call
is already in progress.) -->
@@ -917,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] -->
@@ -1029,9 +921,6 @@
<!-- Label to clear all selection in multiple picker -->
<string name="menu_select_none">"Unselect all"</string>
- <!-- The text displayed when the contacts list is empty while displaying only selected contacts in multiple picker -->
- <string name="no_contacts_selected">"No contacts selected."</string>
-
<!-- The add field button shown in the editor under each editable Raw Contact [CHAR LIMIT=30] -->
<string name="add_field">Add another field</string>
@@ -1094,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 3d7da37..6208018 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/ContactListEmptyView.java b/src/com/android/contacts/ContactListEmptyView.java
deleted file mode 100644
index 40d5152..0000000
--- a/src/com/android/contacts/ContactListEmptyView.java
+++ /dev/null
@@ -1,113 +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;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.IContentService;
-import android.os.RemoteException;
-import android.provider.ContactsContract;
-import android.telephony.TelephonyManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-/**
- * Displays a message when there is nothing to display in a contact list.
- */
-public class ContactListEmptyView extends ScrollView {
-
- private static final String TAG = "ContactListEmptyView";
-
- public ContactListEmptyView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void hide() {
- TextView empty = (TextView) findViewById(R.id.emptyText);
- empty.setVisibility(GONE);
- }
-
- public void show(boolean searchMode, boolean displayOnlyPhones,
- boolean isFavoritesMode, boolean isQueryMode, boolean isShortcutAction,
- boolean isMultipleSelectionEnabled, boolean showSelectedOnly) {
- if (searchMode) {
- return;
- }
-
- TextView empty = (TextView) findViewById(R.id.emptyText);
- Context context = getContext();
- if (displayOnlyPhones) {
- empty.setText(context.getText(R.string.noContactsWithPhoneNumbers));
- } else if (isFavoritesMode) {
- empty.setText(context.getText(R.string.noFavoritesHelpText));
- } else if (isQueryMode) {
- empty.setText(context.getText(R.string.noMatchingContacts));
- } if (isMultipleSelectionEnabled) {
- if (showSelectedOnly) {
- empty.setText(context.getText(R.string.no_contacts_selected));
- } else {
- empty.setText(context.getText(R.string.noContactsWithPhoneNumbers));
- }
- } else {
- TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- boolean hasSim = telephonyManager.hasIccCard();
- if (isSyncActive()) {
- if (isShortcutAction) {
- // Help text is the same no matter whether there is SIM or not.
- empty.setText(
- context.getText(R.string.noContactsHelpTextWithSyncForCreateShortcut));
- } else if (hasSim) {
- empty.setText(context.getText(R.string.noContactsHelpTextWithSync));
- } else {
- empty.setText(context.getText(R.string.noContactsNoSimHelpTextWithSync));
- }
- } else {
- if (isShortcutAction) {
- // Help text is the same no matter whether there is SIM or not.
- empty.setText(context.getText(R.string.noContactsHelpTextForCreateShortcut));
- } else if (hasSim) {
- empty.setText(context.getText(R.string.noContactsHelpText));
- } else {
- empty.setText(context.getText(R.string.noContactsNoSimHelpText));
- }
- }
- }
- empty.setVisibility(VISIBLE);
- }
-
- private boolean isSyncActive() {
- Account[] accounts = AccountManager.get(getContext()).getAccounts();
- if (accounts != null && accounts.length > 0) {
- IContentService contentService = ContentResolver.getContentService();
- for (Account account : accounts) {
- try {
- if (contentService.isSyncActive(account, ContactsContract.AUTHORITY)) {
- return true;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Could not get the sync status");
- }
- }
- }
- return false;
- }
-}
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 64d5531..d87a1a0 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -47,7 +47,7 @@
import android.widget.Toast;
import com.android.contacts.common.database.ContactUpdateUtils;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.RawContactDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index ef07cf9..82b2a25 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -30,8 +30,8 @@
import android.util.Log;
import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.list.ContactListFilterController;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.list.ContactListFilterController;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.test.InjectedServices;
import com.android.contacts.common.util.Constants;
import com.google.common.annotations.VisibleForTesting;
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 57976e5..b68109e 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -26,7 +26,7 @@
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.test.NeededForTesting;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import java.util.List;
diff --git a/src/com/android/contacts/SplitAggregateView.java b/src/com/android/contacts/SplitAggregateView.java
index fabd58b..6e38549 100644
--- a/src/com/android/contacts/SplitAggregateView.java
+++ b/src/com/android/contacts/SplitAggregateView.java
@@ -35,7 +35,7 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 54f2de8..c0a751c 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -39,6 +39,7 @@
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.util.ContactPhotoUtils;
import java.io.File;
@@ -195,7 +196,7 @@
// the ContactSaveService would not create the new contact, and the
// full-res photo would fail to be saved to the non-existent contact.
AccountType account = raw.getRawContactAccountType(this);
- RawContactDelta.ValuesDelta values =
+ ValuesDelta values =
RawContactModifier.ensureKindExists(raw, account, Photo.CONTENT_ITEM_TYPE);
if (values == null) {
Log.w(TAG, "cannot attach photo to this account type");
diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
index 9bd4f45..ae4cf94 100644
--- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
+++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
@@ -61,17 +61,17 @@
import com.android.contacts.R;
import com.android.contacts.editor.Editor;
import com.android.contacts.editor.ViewIdGenerator;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
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/ContactEditorAccountsChangedActivity.java b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
index 13c49e1..26a8eae 100644
--- a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
@@ -30,7 +30,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.ContactEditorUtils;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountsListAdapter;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index efdf7da..d12da85 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -36,7 +36,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.ContactEditorFragment;
import com.android.contacts.editor.ContactEditorFragment.SaveMode;
-import com.android.contacts.model.AccountTypeManager;
+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.android.contacts.util.DialogManager;
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 6822494..b527f84 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -250,7 +250,7 @@
}
private void configureActivityTitle() {
- if (mRequest.getActivityTitle() != null) {
+ if (!TextUtils.isEmpty(mRequest.getActivityTitle())) {
setTitle(mRequest.getActivityTitle());
return;
}
@@ -527,16 +527,6 @@
}
@Override
- public boolean onContextItemSelected(MenuItem item) {
- ContextMenuAdapter menuAdapter = mListFragment.getContextMenuAdapter();
- if (menuAdapter != null) {
- return menuAdapter.onContextItemSelected(item);
- }
-
- return super.onContextItemSelected(item);
- }
-
- @Override
public boolean onQueryTextChange(String newText) {
mListFragment.setQueryString(newText, true);
return false;
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index c2764c3..c24a42f 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -33,7 +33,7 @@
import com.android.contacts.R;
import com.android.contacts.group.GroupDetailDisplayUtils;
import com.android.contacts.group.GroupDetailFragment;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
public class GroupDetailActivity extends ContactsActivity {
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 3a3bdc3..04f0621 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -66,7 +66,7 @@
import com.android.contacts.list.ContactBrowseListFragment;
import com.android.contacts.list.ContactEntryListFragment;
import com.android.contacts.common.list.ContactListFilter;
-import com.android.contacts.list.ContactListFilterController;
+import com.android.contacts.common.list.ContactListFilterController;
import com.android.contacts.common.list.ContactTileAdapter.DisplayType;
import com.android.contacts.list.ContactTileFrequentFragment;
import com.android.contacts.list.ContactTileListFragment;
@@ -83,7 +83,7 @@
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;
@@ -323,7 +323,6 @@
startActivity(redirect);
return false;
}
- setTitle(mRequest.getActivityTitle());
return true;
}
@@ -1245,7 +1244,8 @@
@Override
public void onImportContactsFromFileAction() {
- ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable());
+ ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
+ PeopleActivity.class);
}
@Override
@@ -1535,7 +1535,8 @@
return true;
}
case R.id.menu_import_export: {
- ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable());
+ ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
+ PeopleActivity.class);
return true;
}
case R.id.menu_clear_frequents: {
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index fa71e72..e4af9b8 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -82,11 +82,11 @@
import com.android.contacts.common.GeoUtil;
import com.android.contacts.common.MoreContactUtils;
import com.android.contacts.editor.SelectAccountDialogFragment;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.Contact;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
@@ -1866,6 +1866,11 @@
menu.add(ContextMenu.NONE, ContextMenuIds.COPY_TEXT,
ContextMenu.NONE, getString(R.string.copy_text));
+ // Don't allow setting or clearing of defaults for directory contacts
+ if (mContactData.isDirectoryEntry()) {
+ return;
+ }
+
String selectedMimeType = selectedEntry.mimetype;
// Defaults to true will only enable the detail to be copied to the clipboard.
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index 46e4dad..b578d28 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -31,7 +31,7 @@
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
import com.android.contacts.detail.ContactDetailDisplayUtils.StreamPhotoTag;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.Contact;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.util.StreamItemEntry;
diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java
index c23e239..a239d47 100644
--- a/src/com/android/contacts/detail/ContactLoaderFragment.java
+++ b/src/com/android/contacts/detail/ContactLoaderFragment.java
@@ -42,8 +42,8 @@
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/detail/PhotoSelectionHandler.java b/src/com/android/contacts/detail/PhotoSelectionHandler.java
index d544b30..3f913f2 100644
--- a/src/com/android/contacts/detail/PhotoSelectionHandler.java
+++ b/src/com/android/contacts/detail/PhotoSelectionHandler.java
@@ -39,10 +39,10 @@
import com.android.contacts.R;
import com.android.contacts.editor.PhotoActionPopup;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.util.ContactPhotoUtils;
diff --git a/src/com/android/contacts/detail/StreamItemAdapter.java b/src/com/android/contacts/detail/StreamItemAdapter.java
index 398ac69..5c827dc 100644
--- a/src/com/android/contacts/detail/StreamItemAdapter.java
+++ b/src/com/android/contacts/detail/StreamItemAdapter.java
@@ -23,7 +23,7 @@
import android.widget.BaseAdapter;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.util.StreamItemEntry;
import com.google.common.collect.Lists;
diff --git a/src/com/android/contacts/editor/AggregationSuggestionEngine.java b/src/com/android/contacts/editor/AggregationSuggestionEngine.java
index 0da05e8..2f77858 100644
--- a/src/com/android/contacts/editor/AggregationSuggestionEngine.java
+++ b/src/com/android/contacts/editor/AggregationSuggestionEngine.java
@@ -37,7 +37,7 @@
import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/editor/AggregationSuggestionView.java b/src/com/android/contacts/editor/AggregationSuggestionView.java
index 19481fe..439b1df 100644
--- a/src/com/android/contacts/editor/AggregationSuggestionView.java
+++ b/src/com/android/contacts/editor/AggregationSuggestionView.java
@@ -28,7 +28,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.AggregationSuggestionEngine.RawContact;
import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.google.common.collect.Lists;
diff --git a/src/com/android/contacts/editor/BaseRawContactEditorView.java b/src/com/android/contacts/editor/BaseRawContactEditorView.java
index 1ff9ac2..c39d472 100644
--- a/src/com/android/contacts/editor/BaseRawContactEditorView.java
+++ b/src/com/android/contacts/editor/BaseRawContactEditorView.java
@@ -29,7 +29,7 @@
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType.EditType;
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index b019542..4f6aad5 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -70,12 +70,12 @@
import com.android.contacts.detail.PhotoSelectionHandler;
import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.Contact;
import com.android.contacts.model.ContactLoader;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/src/com/android/contacts/editor/ContactEditorUtils.java b/src/com/android/contacts/editor/ContactEditorUtils.java
index 735f8be..dfbcc6b 100644
--- a/src/com/android/contacts/editor/ContactEditorUtils.java
+++ b/src/com/android/contacts/editor/ContactEditorUtils.java
@@ -27,7 +27,7 @@
import android.util.Log;
import com.android.contacts.common.test.NeededForTesting;
-import com.android.contacts.model.AccountTypeManager;
+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.annotations.VisibleForTesting;
diff --git a/src/com/android/contacts/editor/Editor.java b/src/com/android/contacts/editor/Editor.java
index ec816f7..12ea201 100644
--- a/src/com/android/contacts/editor/Editor.java
+++ b/src/com/android/contacts/editor/Editor.java
@@ -19,7 +19,7 @@
import android.provider.ContactsContract.Data;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
/**
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index 1f6cd43..9c91ff8 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -30,7 +30,7 @@
import com.android.contacts.datepicker.DatePickerDialog;
import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.account.AccountType.EventEditType;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index 97257f1..ab7895c 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -41,7 +41,7 @@
import com.android.contacts.interactions.GroupCreationDialogFragment;
import com.android.contacts.interactions.GroupCreationDialogFragment.OnGroupCreatedListener;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.google.common.base.Objects;
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index 4f70cd4..a119cb2 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -30,7 +30,7 @@
import com.android.contacts.editor.Editor.EditorListener;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index 91339ae..dc7664d 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -47,7 +47,7 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/PhoneticNameEditorView.java b/src/com/android/contacts/editor/PhoneticNameEditorView.java
index 1ee7e21..2836c721 100644
--- a/src/com/android/contacts/editor/PhoneticNameEditorView.java
+++ b/src/com/android/contacts/editor/PhoneticNameEditorView.java
@@ -22,7 +22,7 @@
import android.util.AttributeSet;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.model.dataitem.StructuredNameDataItem;
diff --git a/src/com/android/contacts/editor/PhotoEditorView.java b/src/com/android/contacts/editor/PhotoEditorView.java
index e106eac..652c8e6 100644
--- a/src/com/android/contacts/editor/PhotoEditorView.java
+++ b/src/com/android/contacts/editor/PhotoEditorView.java
@@ -28,7 +28,7 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.util.ContactPhotoUtils;
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 27f2ce4..c79ba2f 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -42,7 +42,7 @@
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.google.common.base.Objects;
diff --git a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
index 8f9dcb9..edfd372 100644
--- a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
+++ b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
@@ -41,7 +41,7 @@
import com.android.contacts.common.GeoUtil;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+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.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
index fcafe75..f709021 100644
--- a/src/com/android/contacts/editor/StructuredNameEditorView.java
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -26,7 +26,7 @@
import android.util.AttributeSet;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.dataitem.DataItem;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.model.dataitem.StructuredNameDataItem;
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index 970bbbf..0c52a2a 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -38,7 +38,7 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.common.util.PhoneNumberFormatter;
diff --git a/src/com/android/contacts/editor/ViewIdGenerator.java b/src/com/android/contacts/editor/ViewIdGenerator.java
index 9f41623..8494e1a 100644
--- a/src/com/android/contacts/editor/ViewIdGenerator.java
+++ b/src/com/android/contacts/editor/ViewIdGenerator.java
@@ -21,7 +21,7 @@
import android.os.Parcelable;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
/**
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
index f96b40d..32296c2 100644
--- a/src/com/android/contacts/group/GroupBrowseListAdapter.java
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.java
@@ -30,7 +30,7 @@
import com.android.contacts.GroupListLoader;
import com.android.contacts.R;
import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.google.common.base.Objects;
/**
diff --git a/src/com/android/contacts/group/GroupDetailDisplayUtils.java b/src/com/android/contacts/group/GroupDetailDisplayUtils.java
index 1cf7831..fb0b0c8 100644
--- a/src/com/android/contacts/group/GroupDetailDisplayUtils.java
+++ b/src/com/android/contacts/group/GroupDetailDisplayUtils.java
@@ -23,7 +23,7 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
public class GroupDetailDisplayUtils {
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index 3ab6bc8..69d5165 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -53,7 +53,7 @@
import com.android.contacts.common.list.ContactTileAdapter;
import com.android.contacts.common.list.ContactTileView;
import com.android.contacts.list.GroupMemberTileAdapter;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
/**
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 20a3334..16b7d86 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -68,7 +68,7 @@
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.editor.SelectAccountDialogFragment;
import com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.util.ViewUtil;
import com.google.common.base.Objects;
diff --git a/src/com/android/contacts/interactions/ContactDeletionInteraction.java b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
index c4387f3..2880f77 100644
--- a/src/com/android/contacts/interactions/ContactDeletionInteraction.java
+++ b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
@@ -35,7 +35,7 @@
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;
diff --git a/src/com/android/contacts/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
index 3f409cb..99b3463 100644
--- a/src/com/android/contacts/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
@@ -39,11 +39,12 @@
import com.android.contacts.R;
import com.android.contacts.editor.SelectAccountDialogFragment;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.vcard.ExportVCardActivity;
+import com.android.contacts.vcard.VCardCommonArguments;
import java.util.List;
@@ -62,10 +63,12 @@
};
/** Preferred way to show this dialog */
- public static void show(FragmentManager fragmentManager, boolean contactsAreAvailable) {
+ public static void show(FragmentManager fragmentManager, boolean contactsAreAvailable,
+ Class callingActivity) {
final ImportExportDialogFragment fragment = new ImportExportDialogFragment();
Bundle args = new Bundle();
args.putBoolean(ARG_CONTACTS_ARE_AVAILABLE, contactsAreAvailable);
+ args.putString(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity.getName());
fragment.setArguments(args);
fragment.show(fragmentManager, ImportExportDialogFragment.TAG);
}
@@ -77,6 +80,8 @@
final LayoutInflater dialogInflater = (LayoutInflater)getActivity()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final boolean contactsAreAvailable = getArguments().getBoolean(ARG_CONTACTS_ARE_AVAILABLE);
+ final String callingActivity = getArguments().getString(
+ VCardCommonArguments.ARG_CALLING_ACTIVITY);
// Adapter that shows a list of string resources
final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(getActivity(),
@@ -125,6 +130,8 @@
case R.string.export_to_sdcard: {
dismissDialog = true;
Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class);
+ exportIntent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY,
+ callingActivity);
getActivity().startActivity(exportIntent);
break;
}
diff --git a/src/com/android/contacts/list/AccountFilterActivity.java b/src/com/android/contacts/list/AccountFilterActivity.java
deleted file mode 100644
index cc986ad..0000000
--- 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.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/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 8ea8c1c..64c4c3d 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -35,12 +35,11 @@
import android.util.Log;
import com.android.common.widget.CompositeCursorAdapter.Partition;
-import com.android.contacts.R;
+import com.android.contacts.common.list.AutoScrollListView;
import com.android.contacts.common.list.ContactListAdapter;
import com.android.contacts.common.list.ContactListFilter;
import com.android.contacts.common.list.DirectoryPartition;
import com.android.contacts.util.ContactLoaderUtils;
-import com.android.contacts.common.list.AutoScrollListView;
import java.util.List;
@@ -276,25 +275,6 @@
checkSelection();
}
- @Override
- protected void prepareEmptyView() {
- if (isSearchMode()) {
- return;
- } else if (isSyncActive()) {
- if (hasIccCard()) {
- setEmptyText(R.string.noContactsHelpTextWithSync);
- } else {
- setEmptyText(R.string.noContactsNoSimHelpTextWithSync);
- }
- } else {
- if (hasIccCard()) {
- setEmptyText(R.string.noContactsHelpText);
- } else {
- setEmptyText(R.string.noContactsNoSimHelpText);
- }
- }
- }
-
public Uri getSelectedContactUri() {
return mSelectedContactUri;
}
@@ -493,8 +473,15 @@
mSelectionRequired = false;
// If we were looking at a different specific contact, just reload
+ // FILTER_TYPE_ALL_ACCOUNTS is needed for the case where a new contact is added
+ // on a tablet and the loader is returning a stale list. In this case, the contact
+ // will not be found until the next load. b/7621855 This will only fix the most
+ // common case where all accounts are shown. It will not fix the one account case.
+ // TODO: we may want to add more FILTER_TYPEs or relax this check to fix all other
+ // FILTER_TYPE cases.
if (mFilter != null
- && mFilter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
+ && (mFilter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT
+ || mFilter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS)) {
reloadData();
} else {
// Otherwise, call the listener, which will adjust the filter.
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index d522b5e..e867b4d 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -16,16 +16,12 @@
package com.android.contacts.list;
-import android.accounts.Account;
-import android.accounts.AccountManager;
import android.app.Activity;
import android.app.Fragment;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.CursorLoader;
-import android.content.IContentService;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
@@ -33,12 +29,8 @@
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.provider.ContactsContract;
import android.provider.ContactsContract.Directory;
-import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -51,17 +43,14 @@
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
-import android.widget.TextView;
import com.android.common.widget.CompositeCursorAdapter.Partition;
-import com.android.contacts.ContactListEmptyView;
import com.android.contacts.R;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.list.ContactEntryListAdapter;
import com.android.contacts.common.list.DirectoryListLoader;
import com.android.contacts.common.list.DirectoryPartition;
import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.widget.ContextMenuAdapter;
/**
* Common base class for various contact-related list fragments.
@@ -128,9 +117,7 @@
private int mSortOrder;
private int mDirectoryResultLimit = DEFAULT_DIRECTORY_RESULT_LIMIT;
- private ContextMenuAdapter mContextMenuAdapter;
private ContactPhotoManager mPhotoManager;
- private ContactListEmptyView mEmptyView;
private ContactsPreferences mContactsPrefs;
private boolean mForceLoad;
@@ -231,10 +218,6 @@
return mListView;
}
- public ContactListEmptyView getEmptyView() {
- return mEmptyView;
- }
-
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -477,13 +460,6 @@
}
/**
- * Configures the empty view. It is called when we are about to populate
- * the list with an empty cursor.
- */
- protected void prepareEmptyView() {
- }
-
- /**
* Shows the count of entries included in the list. The default
* implementation does nothing.
*/
@@ -692,17 +668,6 @@
mDirectoryResultLimit = limit;
}
- public void setContextMenuAdapter(ContextMenuAdapter adapter) {
- mContextMenuAdapter = adapter;
- if (mListView != null) {
- mListView.setOnCreateContextMenuListener(adapter);
- }
- }
-
- public ContextMenuAdapter getContextMenuAdapter() {
- return mContextMenuAdapter;
- }
-
protected boolean loadPreferences() {
boolean changed = false;
if (getContactNameDisplayOrder() != mContactsPrefs.getDisplayOrder()) {
@@ -752,9 +717,6 @@
View emptyView = mView.findViewById(android.R.id.empty);
if (emptyView != null) {
mListView.setEmptyView(emptyView);
- if (emptyView instanceof ContactListEmptyView) {
- mEmptyView = (ContactListEmptyView)emptyView;
- }
}
mListView.setOnItemClickListener(this);
@@ -769,10 +731,6 @@
// We manually save/restore the listview state
mListView.setSaveEnabled(false);
- if (mContextMenuAdapter != null) {
- mListView.setOnCreateContextMenuListener(mContextMenuAdapter);
- }
-
configureVerticalScrollbar();
configurePhotoLoader();
}
@@ -868,14 +826,6 @@
}
/**
- * Dismisses the search UI along with the keyboard if the filter text is empty.
- */
- public void onClose() {
- hideSoftKeyboard();
- finish();
- }
-
- /**
* Restore the list state after the adapter is populated.
*/
protected void completeRestoreInstanceState() {
@@ -885,36 +835,6 @@
}
}
- protected void setEmptyText(int resourceId) {
- TextView empty = (TextView) getEmptyView().findViewById(R.id.emptyText);
- empty.setText(mContext.getText(resourceId));
- empty.setVisibility(View.VISIBLE);
- }
-
- // TODO redesign into an async task or loader
- protected boolean isSyncActive() {
- Account[] accounts = AccountManager.get(mContext).getAccounts();
- if (accounts != null && accounts.length > 0) {
- IContentService contentService = ContentResolver.getContentService();
- for (Account account : accounts) {
- try {
- if (contentService.isSyncActive(account, ContactsContract.AUTHORITY)) {
- return true;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Could not get the sync status");
- }
- }
- }
- return false;
- }
-
- protected boolean hasIccCard() {
- TelephonyManager telephonyManager =
- (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
- return telephonyManager.hasIccCard();
- }
-
public void setDarkTheme(boolean value) {
mDarkTheme = value;
if (mAdapter != null) mAdapter.setDarkTheme(value);
diff --git a/src/com/android/contacts/list/ContactListFilterController.java b/src/com/android/contacts/list/ContactListFilterController.java
deleted file mode 100644
index 569dd5d..0000000
--- a/src/com/android/contacts/list/ContactListFilterController.java
+++ /dev/null
@@ -1,174 +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.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-
-import com.android.contacts.common.list.ContactListFilter;
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Manages {@link com.android.contacts.common.list.ContactListFilter}. All methods must be called from UI thread.
- */
-public abstract class ContactListFilterController {
-
- // singleton to cache the filter controller
- private static ContactListFilterControllerImpl sFilterController = null;
-
- public interface ContactListFilterListener {
- void onContactListFilterChanged();
- }
-
- public static ContactListFilterController getInstance(Context context) {
- // We may need to synchronize this in the future if background task will call this.
- if (sFilterController == null) {
- sFilterController = new ContactListFilterControllerImpl(context);
- }
- return sFilterController;
- }
-
- public abstract void addListener(ContactListFilterListener listener);
-
- public abstract void removeListener(ContactListFilterListener listener);
-
- /**
- * Return the currently-active filter.
- */
- public abstract ContactListFilter getFilter();
-
- /**
- * @param filter the filter
- * @param persistent True when the given filter should be saved soon. False when the filter
- * should not be saved. The latter case may happen when some Intent requires a certain type of
- * UI (e.g. single contact) temporarily.
- */
- public abstract void setContactListFilter(ContactListFilter filter, boolean persistent);
-
- public abstract void selectCustomFilter();
-
- /**
- * Checks if the current filter is valid and reset the filter if not. It may happen when
- * an account is removed while the filter points to the account with
- * {@link ContactListFilter#FILTER_TYPE_ACCOUNT} type, for example. It may also happen if
- * the current filter is {@link ContactListFilter#FILTER_TYPE_SINGLE_CONTACT}, in
- * which case, we should switch to the last saved filter in {@link SharedPreferences}.
- */
- public abstract void checkFilterValidity(boolean notifyListeners);
-}
-
-/**
- * Stores the {@link ContactListFilter} selected by the user and saves it to
- * {@link SharedPreferences} if necessary.
- */
-class ContactListFilterControllerImpl extends ContactListFilterController {
- private final Context mContext;
- private final List<ContactListFilterListener> mListeners =
- new ArrayList<ContactListFilterListener>();
- private ContactListFilter mFilter;
-
- public ContactListFilterControllerImpl(Context context) {
- mContext = context;
- mFilter = ContactListFilter.restoreDefaultPreferences(getSharedPreferences());
- checkFilterValidity(true /* notify listeners */);
- }
-
- @Override
- public void addListener(ContactListFilterListener listener) {
- mListeners.add(listener);
- }
-
- @Override
- public void removeListener(ContactListFilterListener listener) {
- mListeners.remove(listener);
- }
-
- @Override
- public ContactListFilter getFilter() {
- return mFilter;
- }
-
- private SharedPreferences getSharedPreferences() {
- return PreferenceManager.getDefaultSharedPreferences(mContext);
- }
-
- @Override
- public void setContactListFilter(ContactListFilter filter, boolean persistent) {
- setContactListFilter(filter, persistent, true);
- }
-
- private void setContactListFilter(ContactListFilter filter, boolean persistent,
- boolean notifyListeners) {
- if (!filter.equals(mFilter)) {
- mFilter = filter;
- if (persistent) {
- ContactListFilter.storeToPreferences(getSharedPreferences(), mFilter);
- }
- if (notifyListeners && !mListeners.isEmpty()) {
- notifyContactListFilterChanged();
- }
- }
- }
-
- @Override
- public void selectCustomFilter() {
- setContactListFilter(ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_CUSTOM), true);
- }
-
- private void notifyContactListFilterChanged() {
- for (ContactListFilterListener listener : mListeners) {
- listener.onContactListFilterChanged();
- }
- }
-
- @Override
- public void checkFilterValidity(boolean notifyListeners) {
- if (mFilter == null) {
- return;
- }
-
- switch (mFilter.filterType) {
- case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT:
- setContactListFilter(
- ContactListFilter.restoreDefaultPreferences(getSharedPreferences()),
- false, notifyListeners);
- break;
- case ContactListFilter.FILTER_TYPE_ACCOUNT:
- if (!filterAccountExists()) {
- // The current account filter points to invalid account. Use "all" filter
- // instead.
- setContactListFilter(ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS), true, notifyListeners);
- }
- }
- }
-
- /**
- * @return true if the Account for the current filter exists.
- */
- private boolean filterAccountExists() {
- final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
- final AccountWithDataSet filterAccount = new AccountWithDataSet(
- mFilter.accountName, mFilter.accountType, mFilter.dataSet);
- return accountTypeManager.contains(filterAccount, false);
- }
-}
diff --git a/src/com/android/contacts/list/ContactListFilterView.java b/src/com/android/contacts/list/ContactListFilterView.java
deleted file mode 100644
index 8102f65..0000000
--- a/src/com/android/contacts/list/ContactListFilterView.java
+++ /dev/null
@@ -1,143 +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.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.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 2de71be..c8ad712 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.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
@@ -75,10 +76,6 @@
mEditMode = flag;
}
- public boolean isShortcutRequested() {
- return mShortcutRequested;
- }
-
public void setShortcutRequested(boolean flag) {
mShortcutRequested = flag;
}
@@ -185,31 +182,6 @@
}
@Override
- protected void prepareEmptyView() {
- if (isSearchMode()) {
- return;
- } else if (isSyncActive()) {
- if (mShortcutRequested) {
- // Help text is the same no matter whether there is SIM or not.
- setEmptyText(R.string.noContactsHelpTextWithSyncForCreateShortcut);
- } else if (hasIccCard()) {
- setEmptyText(R.string.noContactsHelpTextWithSync);
- } else {
- setEmptyText(R.string.noContactsNoSimHelpTextWithSync);
- }
- } else {
- if (mShortcutRequested) {
- // Help text is the same no matter whether there is SIM or not.
- setEmptyText(R.string.noContactsHelpTextWithSyncForCreateShortcut);
- } else if (hasIccCard()) {
- setEmptyText(R.string.noContactsHelpText);
- } else {
- setEmptyText(R.string.noContactsNoSimHelpText);
- }
- }
- }
-
- @Override
public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) {
mListener.onShortcutIntentCreated(shortcutIntent);
}
diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java
deleted file mode 100644
index 532bbee..0000000
--- 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.model.AccountTypeManager;
-import com.android.contacts.model.RawContactDelta.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 c9c895b..30d5b36 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -34,10 +34,11 @@
import com.android.contacts.R;
import com.android.contacts.common.list.ContactListAdapter;
import com.android.contacts.common.list.ContactListFilter;
+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 c7e4fc2..3fc3135 100644
--- a/src/com/android/contacts/list/PhoneNumberPickerFragment.java
+++ b/src/com/android/contacts/list/PhoneNumberPickerFragment.java
@@ -30,11 +30,13 @@
import com.android.contacts.R;
import com.android.contacts.common.list.ContactEntryListAdapter;
import com.android.contacts.common.list.ContactListFilter;
+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 447328b..0000000
--- 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/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
deleted file mode 100644
index f81179b..0000000
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ /dev/null
@@ -1,824 +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.model;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AuthenticatorDescription;
-import android.accounts.OnAccountsUpdateListener;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.IContentService;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SyncAdapterType;
-import android.content.SyncStatusObserver;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.provider.ContactsContract;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.TimingLogger;
-
-import com.android.contacts.common.MoreContactUtils;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountTypeWithDataSet;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.model.account.ExchangeAccountType;
-import com.android.contacts.common.model.account.ExternalAccountType;
-import com.android.contacts.common.model.account.FallbackAccountType;
-import com.android.contacts.common.model.account.GoogleAccountType;
-import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.common.test.NeededForTesting;
-import com.android.contacts.common.util.Constants;
-import com.android.contacts.list.ContactListFilterController;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Singleton holder for all parsed {@link AccountType} available on the
- * system, typically filled through {@link PackageManager} queries.
- */
-public abstract class AccountTypeManager {
- static final String TAG = "AccountTypeManager";
-
- private static final Object mInitializationLock = new Object();
- private static AccountTypeManager mAccountTypeManager;
-
- /**
- * Requests the singleton instance of {@link AccountTypeManager} with data bound from
- * the available authenticators. This method can safely be called from the UI thread.
- */
- public static AccountTypeManager getInstance(Context context) {
- synchronized (mInitializationLock) {
- if (mAccountTypeManager == null) {
- context = context.getApplicationContext();
- mAccountTypeManager = new AccountTypeManagerImpl(context);
- }
- }
- return mAccountTypeManager;
- }
-
- /**
- * Set the instance of account type manager. This is only for and should only be used by unit
- * tests. While having this method is not ideal, it's simpler than the alternative of
- * holding this as a service in the ContactsApplication context class.
- *
- * @param mockManager The mock AccountTypeManager.
- */
- @NeededForTesting
- public static void setInstanceForTest(AccountTypeManager mockManager) {
- synchronized (mInitializationLock) {
- mAccountTypeManager = mockManager;
- }
- }
-
- /**
- * Returns the list of all accounts (if contactWritableOnly is false) or just the list of
- * contact writable accounts (if contactWritableOnly is true).
- */
- // TODO: Consider splitting this into getContactWritableAccounts() and getAllAccounts()
- public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly);
-
- /**
- * Returns the list of accounts that are group writable.
- */
- public abstract List<AccountWithDataSet> getGroupWritableAccounts();
-
- public abstract AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet);
-
- public final AccountType getAccountType(String accountType, String dataSet) {
- return getAccountType(AccountTypeWithDataSet.get(accountType, dataSet));
- }
-
- public final AccountType getAccountTypeForAccount(AccountWithDataSet account) {
- return getAccountType(account.getAccountTypeWithDataSet());
- }
-
- /**
- * @return Unmodifiable map from {@link AccountTypeWithDataSet}s to {@link AccountType}s
- * which support the "invite" feature and have one or more account.
- *
- * This is a filtered down and more "usable" list compared to
- * {@link #getAllInvitableAccountTypes}, where usable is defined as:
- * (1) making sure that the app that contributed the account type is not disabled
- * (in order to avoid presenting the user with an option that does nothing), and
- * (2) that there is at least one raw contact with that account type in the database
- * (assuming that the user probably doesn't use that account type).
- *
- * Warning: Don't use on the UI thread because this can scan the database.
- */
- public abstract Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes();
-
- /**
- * Find the best {@link DataKind} matching the requested
- * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}.
- * If no direct match found, we try searching {@link FallbackAccountType}.
- */
- public DataKind getKindOrFallback(AccountType type, String mimeType) {
- return type == null ? null : type.getKindForMimetype(mimeType);
- }
-
- /**
- * Returns all registered {@link AccountType}s, including extension ones.
- *
- * @param contactWritableOnly if true, it only returns ones that support writing contacts.
- */
- public abstract List<AccountType> getAccountTypes(boolean contactWritableOnly);
-
- /**
- * @param contactWritableOnly if true, it only returns ones that support writing contacts.
- * @return true when this instance contains the given account.
- */
- public boolean contains(AccountWithDataSet account, boolean contactWritableOnly) {
- for (AccountWithDataSet account_2 : getAccounts(false)) {
- if (account.equals(account_2)) {
- return true;
- }
- }
- return false;
- }
-}
-
-class AccountTypeManagerImpl extends AccountTypeManager
- implements OnAccountsUpdateListener, SyncStatusObserver {
-
- private static final Map<AccountTypeWithDataSet, AccountType>
- EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP =
- Collections.unmodifiableMap(new HashMap<AccountTypeWithDataSet, AccountType>());
-
- /**
- * A sample contact URI used to test whether any activities will respond to an
- * invitable intent with the given URI as the intent data. This doesn't need to be
- * specific to a real contact because an app that intercepts the intent should probably do so
- * for all types of contact URIs.
- */
- private static final Uri SAMPLE_CONTACT_URI = ContactsContract.Contacts.getLookupUri(
- 1, "xxx");
-
- private Context mContext;
- private AccountManager mAccountManager;
-
- private AccountType mFallbackAccountType;
-
- private List<AccountWithDataSet> mAccounts = Lists.newArrayList();
- private List<AccountWithDataSet> mContactWritableAccounts = Lists.newArrayList();
- private List<AccountWithDataSet> mGroupWritableAccounts = Lists.newArrayList();
- private Map<AccountTypeWithDataSet, AccountType> mAccountTypesWithDataSets = Maps.newHashMap();
- private Map<AccountTypeWithDataSet, AccountType> mInvitableAccountTypes =
- EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP;
-
- private final InvitableAccountTypeCache mInvitableAccountTypeCache;
-
- /**
- * The boolean value is equal to true if the {@link InvitableAccountTypeCache} has been
- * initialized. False otherwise.
- */
- private final AtomicBoolean mInvitablesCacheIsInitialized = new AtomicBoolean(false);
-
- /**
- * The boolean value is equal to true if the {@link FindInvitablesTask} is still executing.
- * False otherwise.
- */
- private final AtomicBoolean mInvitablesTaskIsRunning = new AtomicBoolean(false);
-
- private static final int MESSAGE_LOAD_DATA = 0;
- private static final int MESSAGE_PROCESS_BROADCAST_INTENT = 1;
-
- private HandlerThread mListenerThread;
- private Handler mListenerHandler;
-
- private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
- private final Runnable mCheckFilterValidityRunnable = new Runnable () {
- @Override
- public void run() {
- ContactListFilterController.getInstance(mContext).checkFilterValidity(true);
- }
- };
-
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Message msg = mListenerHandler.obtainMessage(MESSAGE_PROCESS_BROADCAST_INTENT, intent);
- mListenerHandler.sendMessage(msg);
- }
-
- };
-
- /* A latch that ensures that asynchronous initialization completes before data is used */
- private volatile CountDownLatch mInitializationLatch = new CountDownLatch(1);
-
- private static final Comparator<Account> ACCOUNT_COMPARATOR = new Comparator<Account>() {
- @Override
- public int compare(Account a, Account b) {
- String aDataSet = null;
- String bDataSet = null;
- if (a instanceof AccountWithDataSet) {
- aDataSet = ((AccountWithDataSet) a).dataSet;
- }
- if (b instanceof AccountWithDataSet) {
- bDataSet = ((AccountWithDataSet) b).dataSet;
- }
-
- if (Objects.equal(a.name, b.name) && Objects.equal(a.type, b.type)
- && Objects.equal(aDataSet, bDataSet)) {
- return 0;
- } else if (b.name == null || b.type == null) {
- return -1;
- } else if (a.name == null || a.type == null) {
- return 1;
- } else {
- int diff = a.name.compareTo(b.name);
- if (diff != 0) {
- return diff;
- }
- diff = a.type.compareTo(b.type);
- if (diff != 0) {
- return diff;
- }
-
- // Accounts without data sets get sorted before those that have them.
- if (aDataSet != null) {
- return bDataSet == null ? 1 : aDataSet.compareTo(bDataSet);
- } else {
- return -1;
- }
- }
- }
- };
-
- /**
- * Internal constructor that only performs initial parsing.
- */
- public AccountTypeManagerImpl(Context context) {
- mContext = context;
- mFallbackAccountType = new FallbackAccountType(context);
-
- mAccountManager = AccountManager.get(mContext);
-
- mListenerThread = new HandlerThread("AccountChangeListener");
- mListenerThread.start();
- mListenerHandler = new Handler(mListenerThread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_LOAD_DATA:
- loadAccountsInBackground();
- break;
- case MESSAGE_PROCESS_BROADCAST_INTENT:
- processBroadcastIntent((Intent) msg.obj);
- break;
- }
- }
- };
-
- mInvitableAccountTypeCache = new InvitableAccountTypeCache();
-
- // Request updates when packages or accounts change
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mBroadcastReceiver, filter);
- IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(mBroadcastReceiver, sdFilter);
-
- // Request updates when locale is changed so that the order of each field will
- // be able to be changed on the locale change.
- filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
- mContext.registerReceiver(mBroadcastReceiver, filter);
-
- mAccountManager.addOnAccountsUpdatedListener(this, mListenerHandler, false);
-
- ContentResolver.addStatusChangeListener(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, this);
-
- mListenerHandler.sendEmptyMessage(MESSAGE_LOAD_DATA);
- }
-
- @Override
- public void onStatusChanged(int which) {
- mListenerHandler.sendEmptyMessage(MESSAGE_LOAD_DATA);
- }
-
- public void processBroadcastIntent(Intent intent) {
- mListenerHandler.sendEmptyMessage(MESSAGE_LOAD_DATA);
- }
-
- /* This notification will arrive on the background thread */
- public void onAccountsUpdated(Account[] accounts) {
- // Refresh to catch any changed accounts
- loadAccountsInBackground();
- }
-
- /**
- * Returns instantly if accounts and account types have already been loaded.
- * Otherwise waits for the background thread to complete the loading.
- */
- void ensureAccountsLoaded() {
- CountDownLatch latch = mInitializationLatch;
- if (latch == null) {
- return;
- }
- while (true) {
- try {
- latch.await();
- return;
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
-
- /**
- * Loads account list and corresponding account types (potentially with data sets). Always
- * called on a background thread.
- */
- protected void loadAccountsInBackground() {
- if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
- Log.d(Constants.PERFORMANCE_TAG, "AccountTypeManager.loadAccountsInBackground start");
- }
- TimingLogger timings = new TimingLogger(TAG, "loadAccountsInBackground");
- final long startTime = SystemClock.currentThreadTimeMillis();
- final long startTimeWall = SystemClock.elapsedRealtime();
-
- // Account types, keyed off the account type and data set concatenation.
- final Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet =
- Maps.newHashMap();
-
- // The same AccountTypes, but keyed off {@link RawContacts#ACCOUNT_TYPE}. Since there can
- // be multiple account types (with different data sets) for the same type of account, each
- // type string may have multiple AccountType entries.
- final Map<String, List<AccountType>> accountTypesByType = Maps.newHashMap();
-
- final List<AccountWithDataSet> allAccounts = Lists.newArrayList();
- final List<AccountWithDataSet> contactWritableAccounts = Lists.newArrayList();
- final List<AccountWithDataSet> groupWritableAccounts = Lists.newArrayList();
- final Set<String> extensionPackages = Sets.newHashSet();
-
- final AccountManager am = mAccountManager;
- final IContentService cs = ContentResolver.getContentService();
-
- try {
- final SyncAdapterType[] syncs = cs.getSyncAdapterTypes();
- final AuthenticatorDescription[] auths = am.getAuthenticatorTypes();
-
- // First process sync adapters to find any that provide contact data.
- for (SyncAdapterType sync : syncs) {
- if (!ContactsContract.AUTHORITY.equals(sync.authority)) {
- // Skip sync adapters that don't provide contact data.
- continue;
- }
-
- // Look for the formatting details provided by each sync
- // adapter, using the authenticator to find general resources.
- final String type = sync.accountType;
- final AuthenticatorDescription auth = findAuthenticator(auths, type);
- if (auth == null) {
- Log.w(TAG, "No authenticator found for type=" + type + ", ignoring it.");
- continue;
- }
-
- AccountType accountType;
- if (GoogleAccountType.ACCOUNT_TYPE.equals(type)) {
- accountType = new GoogleAccountType(mContext, auth.packageName);
- } else if (ExchangeAccountType.isExchangeType(type)) {
- accountType = new ExchangeAccountType(mContext, auth.packageName, type);
- } else {
- // TODO: use syncadapter package instead, since it provides resources
- Log.d(TAG, "Registering external account type=" + type
- + ", packageName=" + auth.packageName);
- accountType = new ExternalAccountType(mContext, auth.packageName, false);
- }
- if (!accountType.isInitialized()) {
- if (accountType.isEmbedded()) {
- throw new IllegalStateException("Problem initializing embedded type "
- + accountType.getClass().getCanonicalName());
- } else {
- // Skip external account types that couldn't be initialized.
- continue;
- }
- }
-
- accountType.accountType = auth.type;
- accountType.titleRes = auth.labelId;
- accountType.iconRes = auth.iconId;
-
- addAccountType(accountType, accountTypesByTypeAndDataSet, accountTypesByType);
-
- // Check to see if the account type knows of any other non-sync-adapter packages
- // that may provide other data sets of contact data.
- extensionPackages.addAll(accountType.getExtensionPackageNames());
- }
-
- // If any extension packages were specified, process them as well.
- if (!extensionPackages.isEmpty()) {
- Log.d(TAG, "Registering " + extensionPackages.size() + " extension packages");
- for (String extensionPackage : extensionPackages) {
- ExternalAccountType accountType =
- new ExternalAccountType(mContext, extensionPackage, true);
- if (!accountType.isInitialized()) {
- // Skip external account types that couldn't be initialized.
- continue;
- }
- if (!accountType.hasContactsMetadata()) {
- Log.w(TAG, "Skipping extension package " + extensionPackage + " because"
- + " it doesn't have the CONTACTS_STRUCTURE metadata");
- continue;
- }
- if (TextUtils.isEmpty(accountType.accountType)) {
- Log.w(TAG, "Skipping extension package " + extensionPackage + " because"
- + " the CONTACTS_STRUCTURE metadata doesn't have the accountType"
- + " attribute");
- continue;
- }
- Log.d(TAG, "Registering extension package account type="
- + accountType.accountType + ", dataSet=" + accountType.dataSet
- + ", packageName=" + extensionPackage);
-
- addAccountType(accountType, accountTypesByTypeAndDataSet, accountTypesByType);
- }
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Problem loading accounts: " + e.toString());
- }
- timings.addSplit("Loaded account types");
-
- // Map in accounts to associate the account names with each account type entry.
- Account[] accounts = mAccountManager.getAccounts();
- for (Account account : accounts) {
- boolean syncable = false;
- try {
- syncable = cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0;
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot obtain sync flag for account: " + account, e);
- }
-
- if (syncable) {
- List<AccountType> accountTypes = accountTypesByType.get(account.type);
- if (accountTypes != null) {
- // Add an account-with-data-set entry for each account type that is
- // authenticated by this account.
- for (AccountType accountType : accountTypes) {
- AccountWithDataSet accountWithDataSet = new AccountWithDataSet(
- account.name, account.type, accountType.dataSet);
- allAccounts.add(accountWithDataSet);
- if (accountType.areContactsWritable()) {
- contactWritableAccounts.add(accountWithDataSet);
- }
- if (accountType.isGroupMembershipEditable()) {
- groupWritableAccounts.add(accountWithDataSet);
- }
- }
- }
- }
- }
-
- Collections.sort(allAccounts, ACCOUNT_COMPARATOR);
- Collections.sort(contactWritableAccounts, ACCOUNT_COMPARATOR);
- Collections.sort(groupWritableAccounts, ACCOUNT_COMPARATOR);
-
- timings.addSplit("Loaded accounts");
-
- synchronized (this) {
- mAccountTypesWithDataSets = accountTypesByTypeAndDataSet;
- mAccounts = allAccounts;
- mContactWritableAccounts = contactWritableAccounts;
- mGroupWritableAccounts = groupWritableAccounts;
- mInvitableAccountTypes = findAllInvitableAccountTypes(
- mContext, allAccounts, accountTypesByTypeAndDataSet);
- }
-
- timings.dumpToLog();
- final long endTimeWall = SystemClock.elapsedRealtime();
- final long endTime = SystemClock.currentThreadTimeMillis();
-
- Log.i(TAG, "Loaded meta-data for " + mAccountTypesWithDataSets.size() + " account types, "
- + mAccounts.size() + " accounts in " + (endTimeWall - startTimeWall) + "ms(wall) "
- + (endTime - startTime) + "ms(cpu)");
-
- if (mInitializationLatch != null) {
- mInitializationLatch.countDown();
- mInitializationLatch = null;
- }
- if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
- Log.d(Constants.PERFORMANCE_TAG, "AccountTypeManager.loadAccountsInBackground finish");
- }
-
- // Check filter validity since filter may become obsolete after account update. It must be
- // done from UI thread.
- mMainThreadHandler.post(mCheckFilterValidityRunnable);
- }
-
- // Bookkeeping method for tracking the known account types in the given maps.
- private void addAccountType(AccountType accountType,
- Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet,
- Map<String, List<AccountType>> accountTypesByType) {
- accountTypesByTypeAndDataSet.put(accountType.getAccountTypeAndDataSet(), accountType);
- List<AccountType> accountsForType = accountTypesByType.get(accountType.accountType);
- if (accountsForType == null) {
- accountsForType = Lists.newArrayList();
- }
- accountsForType.add(accountType);
- accountTypesByType.put(accountType.accountType, accountsForType);
- }
-
- /**
- * Find a specific {@link AuthenticatorDescription} in the provided list
- * that matches the given account type.
- */
- protected static AuthenticatorDescription findAuthenticator(AuthenticatorDescription[] auths,
- String accountType) {
- for (AuthenticatorDescription auth : auths) {
- if (accountType.equals(auth.type)) {
- return auth;
- }
- }
- return null;
- }
-
- /**
- * Return list of all known, contact writable {@link AccountWithDataSet}'s.
- */
- @Override
- public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
- ensureAccountsLoaded();
- return contactWritableOnly ? mContactWritableAccounts : mAccounts;
- }
-
- /**
- * Return the list of all known, group writable {@link AccountWithDataSet}'s.
- */
- public List<AccountWithDataSet> getGroupWritableAccounts() {
- ensureAccountsLoaded();
- return mGroupWritableAccounts;
- }
-
- /**
- * Find the best {@link DataKind} matching the requested
- * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}.
- * If no direct match found, we try searching {@link FallbackAccountType}.
- */
- @Override
- public DataKind getKindOrFallback(AccountType type, String mimeType) {
- ensureAccountsLoaded();
- DataKind kind = null;
-
- // Try finding account type and kind matching request
- if (type != null) {
- kind = type.getKindForMimetype(mimeType);
- }
-
- if (kind == null) {
- // Nothing found, so try fallback as last resort
- kind = mFallbackAccountType.getKindForMimetype(mimeType);
- }
-
- if (kind == null) {
- Log.w(TAG, "Unknown type=" + type + ", mime=" + mimeType);
- }
-
- return kind;
- }
-
- /**
- * Return {@link AccountType} for the given account type and data set.
- */
- @Override
- public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) {
- ensureAccountsLoaded();
- synchronized (this) {
- AccountType type = mAccountTypesWithDataSets.get(accountTypeWithDataSet);
- return type != null ? type : mFallbackAccountType;
- }
- }
-
- /**
- * @return Unmodifiable map from {@link AccountTypeWithDataSet}s to {@link AccountType}s
- * which support the "invite" feature and have one or more account. This is an unfiltered
- * list. See {@link #getUsableInvitableAccountTypes()}.
- */
- private Map<AccountTypeWithDataSet, AccountType> getAllInvitableAccountTypes() {
- ensureAccountsLoaded();
- return mInvitableAccountTypes;
- }
-
- @Override
- public Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes() {
- ensureAccountsLoaded();
- // Since this method is not thread-safe, it's possible for multiple threads to encounter
- // the situation where (1) the cache has not been initialized yet or
- // (2) an async task to refresh the account type list in the cache has already been
- // started. Hence we use {@link AtomicBoolean}s and return cached values immediately
- // while we compute the actual result in the background. We use this approach instead of
- // using "synchronized" because computing the account type list involves a DB read, and
- // can potentially cause a deadlock situation if this method is called from code which
- // holds the DB lock. The trade-off of potentially having an incorrect list of invitable
- // account types for a short period of time seems more manageable than enforcing the
- // context in which this method is called.
-
- // Computing the list of usable invitable account types is done on the fly as requested.
- // If this method has never been called before, then block until the list has been computed.
- if (!mInvitablesCacheIsInitialized.get()) {
- mInvitableAccountTypeCache.setCachedValue(findUsableInvitableAccountTypes(mContext));
- mInvitablesCacheIsInitialized.set(true);
- } else {
- // Otherwise, there is a value in the cache. If the value has expired and
- // an async task has not already been started by another thread, then kick off a new
- // async task to compute the list.
- if (mInvitableAccountTypeCache.isExpired() &&
- mInvitablesTaskIsRunning.compareAndSet(false, true)) {
- new FindInvitablesTask().execute();
- }
- }
-
- return mInvitableAccountTypeCache.getCachedValue();
- }
-
- /**
- * Return all {@link AccountType}s with at least one account which supports "invite", i.e.
- * its {@link AccountType#getInviteContactActivityClassName()} is not empty.
- */
- @VisibleForTesting
- static Map<AccountTypeWithDataSet, AccountType> findAllInvitableAccountTypes(Context context,
- Collection<AccountWithDataSet> accounts,
- Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet) {
- HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap();
- for (AccountWithDataSet account : accounts) {
- AccountTypeWithDataSet accountTypeWithDataSet = account.getAccountTypeWithDataSet();
- AccountType type = accountTypesByTypeAndDataSet.get(accountTypeWithDataSet);
- if (type == null) continue; // just in case
- if (result.containsKey(accountTypeWithDataSet)) continue;
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Type " + accountTypeWithDataSet
- + " inviteClass=" + type.getInviteContactActivityClassName());
- }
- if (!TextUtils.isEmpty(type.getInviteContactActivityClassName())) {
- result.put(accountTypeWithDataSet, type);
- }
- }
- return Collections.unmodifiableMap(result);
- }
-
- /**
- * Return all usable {@link AccountType}s that support the "invite" feature from the
- * list of all potential invitable account types (retrieved from
- * {@link #getAllInvitableAccountTypes}). A usable invitable account type means:
- * (1) there is at least 1 raw contact in the database with that account type, and
- * (2) the app contributing the account type is not disabled.
- *
- * Warning: Don't use on the UI thread because this can scan the database.
- */
- private Map<AccountTypeWithDataSet, AccountType> findUsableInvitableAccountTypes(
- Context context) {
- Map<AccountTypeWithDataSet, AccountType> allInvitables = getAllInvitableAccountTypes();
- if (allInvitables.isEmpty()) {
- return EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP;
- }
-
- final HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap();
- result.putAll(allInvitables);
-
- final PackageManager packageManager = context.getPackageManager();
- for (AccountTypeWithDataSet accountTypeWithDataSet : allInvitables.keySet()) {
- AccountType accountType = allInvitables.get(accountTypeWithDataSet);
-
- // Make sure that account types don't come from apps that are disabled.
- Intent invitableIntent = MoreContactUtils.getInvitableIntent(accountType,
- SAMPLE_CONTACT_URI);
- if (invitableIntent == null) {
- result.remove(accountTypeWithDataSet);
- continue;
- }
- ResolveInfo resolveInfo = packageManager.resolveActivity(invitableIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- if (resolveInfo == null) {
- // If we can't find an activity to start for this intent, then there's no point in
- // showing this option to the user.
- result.remove(accountTypeWithDataSet);
- continue;
- }
-
- // Make sure that there is at least 1 raw contact with this account type. This check
- // is non-trivial and should not be done on the UI thread.
- if (!accountTypeWithDataSet.hasData(context)) {
- result.remove(accountTypeWithDataSet);
- }
- }
-
- return Collections.unmodifiableMap(result);
- }
-
- @Override
- public List<AccountType> getAccountTypes(boolean contactWritableOnly) {
- ensureAccountsLoaded();
- final List<AccountType> accountTypes = Lists.newArrayList();
- synchronized (this) {
- for (AccountType type : mAccountTypesWithDataSets.values()) {
- if (!contactWritableOnly || type.areContactsWritable()) {
- accountTypes.add(type);
- }
- }
- }
- return accountTypes;
- }
-
- /**
- * Background task to find all usable {@link AccountType}s that support the "invite" feature
- * from the list of all potential invitable account types. Once the work is completed,
- * the list of account types is stored in the {@link AccountTypeManager}'s
- * {@link InvitableAccountTypeCache}.
- */
- private class FindInvitablesTask extends AsyncTask<Void, Void,
- Map<AccountTypeWithDataSet, AccountType>> {
-
- @Override
- protected Map<AccountTypeWithDataSet, AccountType> doInBackground(Void... params) {
- return findUsableInvitableAccountTypes(mContext);
- }
-
- @Override
- protected void onPostExecute(Map<AccountTypeWithDataSet, AccountType> accountTypes) {
- mInvitableAccountTypeCache.setCachedValue(accountTypes);
- mInvitablesTaskIsRunning.set(false);
- }
- }
-
- /**
- * This cache holds a list of invitable {@link AccountTypeWithDataSet}s, in the form of a
- * {@link Map<AccountTypeWithDataSet, AccountType>}. Note that the cached value is valid only
- * for {@link #TIME_TO_LIVE} milliseconds.
- */
- private static final class InvitableAccountTypeCache {
-
- /**
- * The cached {@link #mInvitableAccountTypes} list expires after this number of milliseconds
- * has elapsed.
- */
- private static final long TIME_TO_LIVE = 60000;
-
- private Map<AccountTypeWithDataSet, AccountType> mInvitableAccountTypes;
-
- private long mTimeLastSet;
-
- /**
- * Returns true if the data in this cache is stale and needs to be refreshed. Returns false
- * otherwise.
- */
- public boolean isExpired() {
- return SystemClock.elapsedRealtime() - mTimeLastSet > TIME_TO_LIVE;
- }
-
- /**
- * Returns the cached value. Note that the caller is responsible for checking
- * {@link #isExpired()} to ensure that the value is not stale.
- */
- public Map<AccountTypeWithDataSet, AccountType> getCachedValue() {
- return mInvitableAccountTypes;
- }
-
- public void setCachedValue(Map<AccountTypeWithDataSet, AccountType> map) {
- mInvitableAccountTypes = map;
- mTimeLastSet = SystemClock.elapsedRealtime();
- }
- }
-}
diff --git a/src/com/android/contacts/model/ContactLoader.java b/src/com/android/contacts/model/ContactLoader.java
index 6259800..3c1fc9d 100644
--- a/src/com/android/contacts/model/ContactLoader.java
+++ b/src/com/android/contacts/model/ContactLoader.java
@@ -43,6 +43,7 @@
import com.android.contacts.GroupMetaData;
import com.android.contacts.common.GeoUtil;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountTypeWithDataSet;
import com.android.contacts.model.dataitem.DataItem;
diff --git a/src/com/android/contacts/model/RawContact.java b/src/com/android/contacts/model/RawContact.java
index c4e5f3e..9ded00e 100644
--- a/src/com/android/contacts/model/RawContact.java
+++ b/src/com/android/contacts/model/RawContact.java
@@ -26,6 +26,7 @@
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
+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.android.contacts.model.dataitem.DataItem;
diff --git a/src/com/android/contacts/model/RawContactDelta.java b/src/com/android/contacts/model/RawContactDelta.java
index f7ddcc9..373eabd 100644
--- a/src/com/android/contacts/model/RawContactDelta.java
+++ b/src/com/android/contacts/model/RawContactDelta.java
@@ -24,27 +24,21 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.BaseColumns;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContacts;
import android.util.Log;
+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.test.NeededForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+
/**
* Contains a {@link RawContact} and records any modifications separately so the
* original {@link RawContact} can be swapped out with a newer version and the
@@ -559,544 +553,4 @@
}
};
- /**
- * Type of {@link ContentValues} that maintains both an original state and a
- * modified version of that state. This allows us to build insert, update,
- * or delete operations based on a "before" {@link Entity} snapshot.
- */
- public static class ValuesDelta implements Parcelable {
- protected ContentValues mBefore;
- protected ContentValues mAfter;
- protected String mIdColumn = BaseColumns._ID;
- private boolean mFromTemplate;
-
- /**
- * Next value to assign to {@link #mIdColumn} when building an insert
- * operation through {@link #fromAfter(ContentValues)}. This is used so
- * we can concretely reference this {@link ValuesDelta} before it has
- * been persisted.
- */
- protected static int sNextInsertId = -1;
-
- protected ValuesDelta() {
- }
-
- /**
- * Create {@link ValuesDelta}, using the given object as the
- * "before" state, usually from an {@link Entity}.
- */
- public static ValuesDelta fromBefore(ContentValues before) {
- final ValuesDelta entry = new ValuesDelta();
- entry.mBefore = before;
- entry.mAfter = new ContentValues();
- return entry;
- }
-
- /**
- * Create {@link ValuesDelta}, using the given object as the "after"
- * state, usually when we are inserting a row instead of updating.
- */
- public static ValuesDelta fromAfter(ContentValues after) {
- final ValuesDelta entry = new ValuesDelta();
- entry.mBefore = null;
- entry.mAfter = after;
-
- // Assign temporary id which is dropped before insert.
- entry.mAfter.put(entry.mIdColumn, sNextInsertId--);
- return entry;
- }
-
- @NeededForTesting
- public ContentValues getAfter() {
- return mAfter;
- }
-
- public boolean containsKey(String key) {
- return ((mAfter != null && mAfter.containsKey(key)) ||
- (mBefore != null && mBefore.containsKey(key)));
- }
-
- public String getAsString(String key) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsString(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsString(key);
- } else {
- return null;
- }
- }
-
- public byte[] getAsByteArray(String key) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsByteArray(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsByteArray(key);
- } else {
- return null;
- }
- }
-
- public Long getAsLong(String key) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsLong(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsLong(key);
- } else {
- return null;
- }
- }
-
- public Integer getAsInteger(String key) {
- return getAsInteger(key, null);
- }
-
- public Integer getAsInteger(String key, Integer defaultValue) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsInteger(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsInteger(key);
- } else {
- return defaultValue;
- }
- }
-
- public boolean isChanged(String key) {
- if (mAfter == null || !mAfter.containsKey(key)) {
- return false;
- }
-
- Object newValue = mAfter.get(key);
- Object oldValue = mBefore.get(key);
-
- if (oldValue == null) {
- return newValue != null;
- }
-
- return !oldValue.equals(newValue);
- }
-
- public String getMimetype() {
- return getAsString(Data.MIMETYPE);
- }
-
- public Long getId() {
- return getAsLong(mIdColumn);
- }
-
- public void setIdColumn(String idColumn) {
- mIdColumn = idColumn;
- }
-
- public boolean isPrimary() {
- final Long isPrimary = getAsLong(Data.IS_PRIMARY);
- return isPrimary == null ? false : isPrimary != 0;
- }
-
- public void setFromTemplate(boolean isFromTemplate) {
- mFromTemplate = isFromTemplate;
- }
-
- public boolean isFromTemplate() {
- return mFromTemplate;
- }
-
- public boolean isSuperPrimary() {
- final Long isSuperPrimary = getAsLong(Data.IS_SUPER_PRIMARY);
- return isSuperPrimary == null ? false : isSuperPrimary != 0;
- }
-
- public boolean beforeExists() {
- return (mBefore != null && mBefore.containsKey(mIdColumn));
- }
-
- /**
- * When "after" is present, then visible
- */
- public boolean isVisible() {
- return (mAfter != null);
- }
-
- /**
- * When "after" is wiped, action is "delete"
- */
- public boolean isDelete() {
- return beforeExists() && (mAfter == null);
- }
-
- /**
- * When no "before" or "after", is transient
- */
- public boolean isTransient() {
- return (mBefore == null) && (mAfter == null);
- }
-
- /**
- * When "after" has some changes, action is "update"
- */
- public boolean isUpdate() {
- if (!beforeExists() || mAfter == null || mAfter.size() == 0) {
- return false;
- }
- for (String key : mAfter.keySet()) {
- Object newValue = mAfter.get(key);
- Object oldValue = mBefore.get(key);
- if (oldValue == null) {
- if (newValue != null) {
- return true;
- }
- } else if (!oldValue.equals(newValue)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * When "after" has no changes, action is no-op
- */
- public boolean isNoop() {
- return beforeExists() && (mAfter != null && mAfter.size() == 0);
- }
-
- /**
- * When no "before" id, and has "after", action is "insert"
- */
- public boolean isInsert() {
- return !beforeExists() && (mAfter != null);
- }
-
- public void markDeleted() {
- mAfter = null;
- }
-
- /**
- * Ensure that our internal structure is ready for storing updates.
- */
- private void ensureUpdate() {
- if (mAfter == null) {
- mAfter = new ContentValues();
- }
- }
-
- public void put(String key, String value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void put(String key, byte[] value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void put(String key, int value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void put(String key, long value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void putNull(String key) {
- ensureUpdate();
- mAfter.putNull(key);
- }
-
- public void copyStringFrom(ValuesDelta from, String key) {
- ensureUpdate();
- put(key, from.getAsString(key));
- }
-
- /**
- * Return set of all keys defined through this object.
- */
- public Set<String> keySet() {
- final HashSet<String> keys = Sets.newHashSet();
-
- if (mBefore != null) {
- for (Map.Entry<String, Object> entry : mBefore.valueSet()) {
- keys.add(entry.getKey());
- }
- }
-
- if (mAfter != null) {
- for (Map.Entry<String, Object> entry : mAfter.valueSet()) {
- keys.add(entry.getKey());
- }
- }
-
- return keys;
- }
-
- /**
- * Return complete set of "before" and "after" values mixed together,
- * giving full state regardless of edits.
- */
- public ContentValues getCompleteValues() {
- final ContentValues values = new ContentValues();
- if (mBefore != null) {
- values.putAll(mBefore);
- }
- if (mAfter != null) {
- values.putAll(mAfter);
- }
- if (values.containsKey(GroupMembership.GROUP_ROW_ID)) {
- // Clear to avoid double-definitions, and prefer rows
- values.remove(GroupMembership.GROUP_SOURCE_ID);
- }
-
- return values;
- }
-
- /**
- * Merge the "after" values from the given {@link ValuesDelta},
- * discarding any existing "after" state. This is typically used when
- * re-parenting changes onto an updated {@link Entity}.
- */
- public static ValuesDelta mergeAfter(ValuesDelta local, ValuesDelta remote) {
- // Bail early if trying to merge delete with missing local
- if (local == null && (remote.isDelete() || remote.isTransient())) return null;
-
- // Create local version if none exists yet
- if (local == null) local = new ValuesDelta();
-
- if (!local.beforeExists()) {
- // Any "before" record is missing, so take all values as "insert"
- local.mAfter = remote.getCompleteValues();
- } else {
- // Existing "update" with only "after" values
- local.mAfter = remote.mAfter;
- }
-
- return local;
- }
-
- @Override
- public boolean equals(Object object) {
- if (object instanceof ValuesDelta) {
- // Only exactly equal with both are identical subsets
- final ValuesDelta other = (ValuesDelta)object;
- return this.subsetEquals(other) && other.subsetEquals(this);
- }
- return false;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- toString(builder);
- return builder.toString();
- }
-
- /**
- * Helper for building string representation, leveraging the given
- * {@link StringBuilder} to minimize allocations.
- */
- public void toString(StringBuilder builder) {
- builder.append("{ ");
- builder.append("IdColumn=");
- builder.append(mIdColumn);
- builder.append(", FromTemplate=");
- builder.append(mFromTemplate);
- builder.append(", ");
- for (String key : this.keySet()) {
- builder.append(key);
- builder.append("=");
- builder.append(this.getAsString(key));
- builder.append(", ");
- }
- builder.append("}");
- }
-
- /**
- * Check if the given {@link ValuesDelta} is both a subset of this
- * object, and any defined keys have equal values.
- */
- public boolean subsetEquals(ValuesDelta other) {
- for (String key : this.keySet()) {
- final String ourValue = this.getAsString(key);
- final String theirValue = other.getAsString(key);
- if (ourValue == null) {
- // If they have value when we're null, no match
- if (theirValue != null) return false;
- } else {
- // If both values defined and aren't equal, no match
- if (!ourValue.equals(theirValue)) return false;
- }
- }
- // All values compared and matched
- return true;
- }
-
- /**
- * Build a {@link ContentProviderOperation} that will transform our
- * "before" state into our "after" state, using insert, update, or
- * delete as needed.
- */
- public ContentProviderOperation.Builder buildDiff(Uri targetUri) {
- Builder builder = null;
- if (isInsert()) {
- // Changed values are "insert" back-referenced to Contact
- mAfter.remove(mIdColumn);
- builder = ContentProviderOperation.newInsert(targetUri);
- builder.withValues(mAfter);
- } else if (isDelete()) {
- // When marked for deletion and "before" exists, then "delete"
- builder = ContentProviderOperation.newDelete(targetUri);
- builder.withSelection(mIdColumn + "=" + getId(), null);
- } else if (isUpdate()) {
- // When has changes and "before" exists, then "update"
- builder = ContentProviderOperation.newUpdate(targetUri);
- builder.withSelection(mIdColumn + "=" + getId(), null);
- builder.withValues(mAfter);
- }
- return builder;
- }
-
- /** {@inheritDoc} */
- public int describeContents() {
- // Nothing special about this parcel
- return 0;
- }
-
- /** {@inheritDoc} */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mBefore, flags);
- dest.writeParcelable(mAfter, flags);
- dest.writeString(mIdColumn);
- }
-
- public void readFromParcel(Parcel source) {
- final ClassLoader loader = getClass().getClassLoader();
- mBefore = source.<ContentValues> readParcelable(loader);
- mAfter = source.<ContentValues> readParcelable(loader);
- mIdColumn = source.readString();
- }
-
- public static final Parcelable.Creator<ValuesDelta> CREATOR = new Parcelable.Creator<ValuesDelta>() {
- public ValuesDelta createFromParcel(Parcel in) {
- final ValuesDelta values = new ValuesDelta();
- values.readFromParcel(in);
- return values;
- }
-
- public ValuesDelta[] newArray(int size) {
- return new ValuesDelta[size];
- }
- };
-
- public void setGroupRowId(long groupId) {
- put(GroupMembership.GROUP_ROW_ID, groupId);
- }
-
- public Long getGroupRowId() {
- return getAsLong(GroupMembership.GROUP_ROW_ID);
- }
-
- public void setPhoto(byte[] value) {
- put(Photo.PHOTO, value);
- }
-
- public byte[] getPhoto() {
- return getAsByteArray(Photo.PHOTO);
- }
-
- public void setSuperPrimary(boolean val) {
- if (val) {
- put(Data.IS_SUPER_PRIMARY, 1);
- } else {
- put(Data.IS_SUPER_PRIMARY, 0);
- }
- }
-
- public void setPhoneticFamilyName(String value) {
- put(StructuredName.PHONETIC_FAMILY_NAME, value);
- }
-
- public void setPhoneticMiddleName(String value) {
- put(StructuredName.PHONETIC_MIDDLE_NAME, value);
- }
-
- public void setPhoneticGivenName(String value) {
- put(StructuredName.PHONETIC_GIVEN_NAME, value);
- }
-
- public String getPhoneticFamilyName() {
- return getAsString(StructuredName.PHONETIC_FAMILY_NAME);
- }
-
- public String getPhoneticMiddleName() {
- return getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
- }
-
- public String getPhoneticGivenName() {
- return getAsString(StructuredName.PHONETIC_GIVEN_NAME);
- }
-
- public String getDisplayName() {
- return getAsString(StructuredName.DISPLAY_NAME);
- }
-
- public void setDisplayName(String name) {
- if (name == null) {
- putNull(StructuredName.DISPLAY_NAME);
- } else {
- put(StructuredName.DISPLAY_NAME, name);
- }
- }
-
- public void copyStructuredNameFieldsFrom(ValuesDelta name) {
- copyStringFrom(name, StructuredName.DISPLAY_NAME);
-
- copyStringFrom(name, StructuredName.GIVEN_NAME);
- copyStringFrom(name, StructuredName.FAMILY_NAME);
- copyStringFrom(name, StructuredName.PREFIX);
- copyStringFrom(name, StructuredName.MIDDLE_NAME);
- copyStringFrom(name, StructuredName.SUFFIX);
-
- copyStringFrom(name, StructuredName.PHONETIC_GIVEN_NAME);
- copyStringFrom(name, StructuredName.PHONETIC_MIDDLE_NAME);
- copyStringFrom(name, StructuredName.PHONETIC_FAMILY_NAME);
-
- copyStringFrom(name, StructuredName.FULL_NAME_STYLE);
- copyStringFrom(name, StructuredName.PHONETIC_NAME_STYLE);
- }
-
- public String getPhoneNumber() {
- return getAsString(Phone.NUMBER);
- }
-
- public String getPhoneNormalizedNumber() {
- return getAsString(Phone.NORMALIZED_NUMBER);
- }
-
- public boolean phoneHasType() {
- return containsKey(Phone.TYPE);
- }
-
- public int getPhoneType() {
- return getAsInteger(Phone.TYPE);
- }
-
- public String getPhoneLabel() {
- return getAsString(Phone.LABEL);
- }
-
- public String getEmailData() {
- return getAsString(Email.DATA);
- }
-
- public boolean emailHasType() {
- return containsKey(Email.TYPE);
- }
-
- public int getEmailType() {
- return getAsInteger(Email.TYPE);
- }
-
- public String getEmailLabel() {
- return getAsString(Email.LABEL);
- }
- }
}
diff --git a/src/com/android/contacts/model/RawContactDeltaList.java b/src/com/android/contacts/model/RawContactDeltaList.java
index 82dd494..600a751 100644
--- a/src/com/android/contacts/model/RawContactDeltaList.java
+++ b/src/com/android/contacts/model/RawContactDeltaList.java
@@ -30,7 +30,7 @@
import android.provider.ContactsContract.RawContacts;
import android.util.Log;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/model/RawContactModifier.java b/src/com/android/contacts/model/RawContactModifier.java
index 1b8d0fe..f1f5697 100644
--- a/src/com/android/contacts/model/RawContactModifier.java
+++ b/src/com/android/contacts/model/RawContactModifier.java
@@ -47,10 +47,11 @@
import android.util.SparseIntArray;
import com.android.contacts.ContactsUtils;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.util.CommonDateUtils;
import com.android.contacts.editor.EventFieldEditorView;
import com.android.contacts.editor.PhoneticNameEditorView;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.account.AccountType.EditType;
diff --git a/src/com/android/contacts/model/dataitem/DataItem.java b/src/com/android/contacts/model/dataitem/DataItem.java
index 38d0c03..f1b2ccc 100644
--- a/src/com/android/contacts/model/dataitem/DataItem.java
+++ b/src/com/android/contacts/model/dataitem/DataItem.java
@@ -154,4 +154,15 @@
CharSequence actionBody = kind.actionBody.inflateUsing(context, mContentValues);
return actionBody == null ? null : actionBody.toString();
}
+
+ /**
+ * This builds the data string(intended for display) depending on the type of data item. It
+ * returns the same value as {@link #buildDataString} by default, but certain data items can
+ * override it to provide their version of formatted data strings.
+ *
+ * @return Data string representing the data item, possibly formatted for display
+ */
+ public String buildDataStringForDisplay(Context context, DataKind kind) {
+ return buildDataString(context, kind);
+ }
}
diff --git a/src/com/android/contacts/model/dataitem/PhoneDataItem.java b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
index 66b9018..c69bee1 100644
--- a/src/com/android/contacts/model/dataitem/PhoneDataItem.java
+++ b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
@@ -17,10 +17,13 @@
package com.android.contacts.model.dataitem;
import android.content.ContentValues;
+import android.content.Context;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telephony.PhoneNumberUtils;
+import com.android.contacts.common.model.dataitem.DataKind;
+
/**
* Represents a phone data item, wrapping the columns in
* {@link ContactsContract.CommonDataKinds.Phone}.
@@ -68,4 +71,17 @@
}
}
+ /**
+ * Returns the formatted phone number (if already computed using {@link
+ * #computeFormattedPhoneNumber}). Otherwise this method returns the unformatted phone number.
+ */
+ @Override
+ public String buildDataStringForDisplay(Context context, DataKind kind) {
+ final String formatted = getFormattedPhoneNumber();
+ if (formatted != null) {
+ return formatted;
+ } else {
+ return getNumber();
+ }
+ }
}
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index 90a97de..1bf332e 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -96,7 +96,7 @@
}
mIsPrimary = item.isSuperPrimary();
- mBody = item.buildDataString(context, kind);
+ mBody = item.buildDataStringForDisplay(context, kind);
mDataId = item.getId();
mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, mDataId);
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index a585dbe..00ac7ba 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -58,7 +58,7 @@
import com.android.contacts.common.Collapser;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.Contact;
import com.android.contacts.model.ContactLoader;
import com.android.contacts.model.RawContact;
@@ -551,7 +551,10 @@
if (mLookupUri == null) {
Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
}
- return new ContactLoader(getApplicationContext(), mLookupUri, false);
+ return new ContactLoader(getApplicationContext(), mLookupUri,
+ false /*loadGroupMetaData*/, false /*loadStreamItems*/,
+ false /*loadInvitableAccountTypes*/, false /*postViewNotification*/,
+ true /*computeFormattedPhoneNumber*/);
}
};
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index 5c584b4..40c29b9 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -38,7 +38,7 @@
import android.widget.RemoteViews;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.Contact;
import com.android.contacts.model.ContactLoader;
import com.android.contacts.common.model.account.AccountType;
diff --git a/src/com/android/contacts/util/AccountFilterUtil.java b/src/com/android/contacts/util/AccountFilterUtil.java
deleted file mode 100644
index a6df994..0000000
--- 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.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/AccountSelectionUtil.java b/src/com/android/contacts/util/AccountSelectionUtil.java
index d3c9d14..1d456b3 100644
--- a/src/com/android/contacts/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/util/AccountSelectionUtil.java
@@ -31,7 +31,7 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java
index 2740049..a2891a8 100644
--- a/src/com/android/contacts/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/util/AccountsListAdapter.java
@@ -26,7 +26,7 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
diff --git a/src/com/android/contacts/util/EmptyService.java b/src/com/android/contacts/util/EmptyService.java
deleted file mode 100644
index 2e6a159..0000000
--- 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 ec0b812..0000000
--- 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 f60cfd7..0000000
--- 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
- }
-}
diff --git a/src/com/android/contacts/vcard/ExportProcessor.java b/src/com/android/contacts/vcard/ExportProcessor.java
index 12f9e24..6063629 100644
--- a/src/com/android/contacts/vcard/ExportProcessor.java
+++ b/src/com/android/contacts/vcard/ExportProcessor.java
@@ -28,7 +28,6 @@
import android.util.Log;
import com.android.contacts.R;
-import com.android.contacts.activities.PeopleActivity;
import com.android.vcard.VCardComposer;
import com.android.vcard.VCardConfig;
@@ -52,17 +51,21 @@
private final NotificationManager mNotificationManager;
private final ExportRequest mExportRequest;
private final int mJobId;
+ private final String mCallingActivity;
+
private volatile boolean mCanceled;
private volatile boolean mDone;
- public ExportProcessor(VCardService service, ExportRequest exportRequest, int jobId) {
+ public ExportProcessor(VCardService service, ExportRequest exportRequest, int jobId,
+ String callingActivity) {
mService = service;
mResolver = service.getContentResolver();
mNotificationManager =
(NotificationManager)mService.getSystemService(Context.NOTIFICATION_SERVICE);
mExportRequest = exportRequest;
mJobId = jobId;
+ mCallingActivity = callingActivity;
}
@Override
@@ -254,7 +257,8 @@
private void doFinishNotification(final String title, final String description) {
if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description);
- final Intent intent = new Intent(mService, PeopleActivity.class);
+ final Intent intent = new Intent();
+ intent.setClassName(mService, mCallingActivity);
final Notification notification =
NotificationImportExportListener.constructFinishNotification(mService, title,
description, intent);
diff --git a/src/com/android/contacts/vcard/ExportVCardActivity.java b/src/com/android/contacts/vcard/ExportVCardActivity.java
index 6bed577..29ffc4c 100644
--- a/src/com/android/contacts/vcard/ExportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ExportVCardActivity.java
@@ -165,7 +165,10 @@
return;
}
+ final String callingActivity = getIntent().getExtras()
+ .getString(VCardCommonArguments.ARG_CALLING_ACTIVITY);
Intent intent = new Intent(this, VCardService.class);
+ intent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity);
if (startService(intent) == null) {
Log.e(LOG_TAG, "Failed to start vCard service");
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
index a741ba3..d6cad88 100644
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ImportVCardActivity.java
@@ -48,7 +48,7 @@
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.vcard.VCardEntryCounter;
@@ -998,14 +998,6 @@
}
}
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- // This Activity should finish itself on orientation change, and give the main screen back
- // to the caller Activity.
- finish();
- }
-
/**
* Scans vCard in external storage (typically SDCard) and tries to import it.
* - When there's no SDCard available, an error dialog is shown.
diff --git a/src/com/android/contacts/vcard/NfcImportVCardActivity.java b/src/com/android/contacts/vcard/NfcImportVCardActivity.java
index c181dfa..3c099cb 100644
--- a/src/com/android/contacts/vcard/NfcImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/NfcImportVCardActivity.java
@@ -32,7 +32,7 @@
import android.util.Log;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.vcard.VCardEntry;
import com.android.vcard.VCardEntryCounter;
diff --git a/src/com/android/contacts/vcard/SelectAccountActivity.java b/src/com/android/contacts/vcard/SelectAccountActivity.java
index 9185244..f74cc8c 100644
--- a/src/com/android/contacts/vcard/SelectAccountActivity.java
+++ b/src/com/android/contacts/vcard/SelectAccountActivity.java
@@ -23,7 +23,7 @@
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountSelectionUtil;
diff --git a/src/com/android/contacts/vcard/VCardCommonArguments.java b/src/com/android/contacts/vcard/VCardCommonArguments.java
new file mode 100644
index 0000000..06b49a2
--- /dev/null
+++ b/src/com/android/contacts/vcard/VCardCommonArguments.java
@@ -0,0 +1,27 @@
+/*
+ * 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.vcard;
+
+/**
+ * Argument constants used by many activities and services.
+ */
+public class VCardCommonArguments {
+
+ // Argument used to pass calling activities to the target activity or service.
+ // The value should be a string class name (e.g. com.android.contacts.vcard.VCardCommonArgs)
+ public static final String ARG_CALLING_ACTIVITY = "CALLING_ACTIVITY";
+}
diff --git a/src/com/android/contacts/vcard/VCardService.java b/src/com/android/contacts/vcard/VCardService.java
index 74ce69c..056f89a 100644
--- a/src/com/android/contacts/vcard/VCardService.java
+++ b/src/com/android/contacts/vcard/VCardService.java
@@ -128,6 +128,8 @@
private String mErrorReason;
private MyBinder mBinder;
+ private String mCallingActivity;
+
// File names currently reserved by some export job.
private final Set<String> mReservedDestination = new HashSet<String>();
/* ** end of vCard exporter params ** */
@@ -173,6 +175,8 @@
@Override
public int onStartCommand(Intent intent, int flags, int id) {
+ mCallingActivity = intent.getExtras().getString(
+ VCardCommonArguments.ARG_CALLING_ACTIVITY);
return START_STICKY;
}
@@ -223,7 +227,7 @@
public synchronized void handleExportRequest(ExportRequest request,
VCardImportExportListener listener) {
- if (tryExecute(new ExportProcessor(this, request, mCurrentJobId))) {
+ if (tryExecute(new ExportProcessor(this, request, mCurrentJobId, mCallingActivity))) {
final String path = request.destUri.getEncodedPath();
if (DEBUG) Log.d(LOG_TAG, "Reserve the path " + path);
if (!mReservedDestination.add(path)) {
diff --git a/tests/src/com/android/contacts/RawContactDeltaListTests.java b/tests/src/com/android/contacts/RawContactDeltaListTests.java
index ef7667b..a8c445b 100644
--- a/tests/src/com/android/contacts/RawContactDeltaListTests.java
+++ b/tests/src/com/android/contacts/RawContactDeltaListTests.java
@@ -37,7 +37,7 @@
import com.android.contacts.RawContactModifierTests.MockContactsSource;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/tests/src/com/android/contacts/RawContactDeltaTests.java b/tests/src/com/android/contacts/RawContactDeltaTests.java
index 751d41c..dc4eb53 100644
--- a/tests/src/com/android/contacts/RawContactDeltaTests.java
+++ b/tests/src/com/android/contacts/RawContactDeltaTests.java
@@ -34,7 +34,7 @@
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
@@ -143,49 +143,6 @@
assertEquals("Unexpected change when merging", source, merged);
}
- /**
- * Test that {@link ValuesDelta#buildDiff(android.net.Uri)} is correctly
- * built for insert, update, and delete cases. Note this only tests behavior
- * for individual {@link Data} rows.
- */
- public void testValuesDiffNone() {
- final ContentValues before = new ContentValues();
- before.put(Data._ID, TEST_PHONE_ID);
- before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
-
- final ValuesDelta values = ValuesDelta.fromBefore(before);
-
- // None action shouldn't produce a builder
- final Builder builder = values.buildDiff(Data.CONTENT_URI);
- assertNull("None action produced a builder", builder);
- }
-
- public void testValuesDiffInsert() {
- final ContentValues after = new ContentValues();
- after.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
-
- final ValuesDelta values = ValuesDelta.fromAfter(after);
-
- // Should produce an insert action
- final Builder builder = values.buildDiff(Data.CONTENT_URI);
- final int type = builder.build().getType();
- assertEquals("Didn't produce insert action", TYPE_INSERT, type);
- }
-
- public void testValuesDiffUpdate() {
- final ContentValues before = new ContentValues();
- before.put(Data._ID, TEST_PHONE_ID);
- before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
-
- final ValuesDelta values = ValuesDelta.fromBefore(before);
- values.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
-
- // Should produce an update action
- final Builder builder = values.buildDiff(Data.CONTENT_URI);
- final int type = builder.build().getType();
- assertEquals("Didn't produce update action", TYPE_UPDATE, type);
- }
-
public void testValuesDiffDelete() {
final ContentValues before = new ContentValues();
before.put(Data._ID, TEST_PHONE_ID);
diff --git a/tests/src/com/android/contacts/RawContactModifierTests.java b/tests/src/com/android/contacts/RawContactModifierTests.java
index bb0945b..8008cd0 100644
--- a/tests/src/com/android/contacts/RawContactModifierTests.java
+++ b/tests/src/com/android/contacts/RawContactModifierTests.java
@@ -38,10 +38,10 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/tests/src/com/android/contacts/activities/PeopleActivityTest.java b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
index 2fb1040..4ede006 100644
--- a/tests/src/com/android/contacts/activities/PeopleActivityTest.java
+++ b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
@@ -41,7 +41,7 @@
import com.android.contacts.detail.ContactDetailFragment;
import com.android.contacts.interactions.TestLoaderManager;
import com.android.contacts.list.ContactBrowseListFragment;
-import com.android.contacts.model.AccountTypeManager;
+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.android.contacts.common.model.account.BaseAccountType;
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index a89ddc9..34f1e4b 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -31,7 +31,7 @@
import com.android.contacts.common.test.mocks.ContactsMockContext;
import com.android.contacts.common.test.mocks.MockContentProvider;
import com.android.contacts.common.test.mocks.MockContentProvider.Query;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.BaseAccountType;
import com.android.contacts.test.InjectedServices;
diff --git a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java b/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
deleted file mode 100644
index 8cc4e12..0000000
--- a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
+++ /dev/null
@@ -1,198 +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.model;
-
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountTypeWithDataSet;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Test case for {@link AccountTypeManager}.
- *
- * adb shell am instrument -w -e class com.android.contacts.model.AccountTypeManagerTest \
- com.android.contacts.tests/android.test.InstrumentationTestRunner
- */
-@SmallTest
-public class AccountTypeManagerTest extends AndroidTestCase {
- public void testFindAllInvitableAccountTypes() {
- final Context c = getContext();
-
- // Define account types.
- final AccountType typeA = new MockAccountType("type1", null, null);
- final AccountType typeB = new MockAccountType("type1", "minus", null);
- final AccountType typeC = new MockAccountType("type2", null, "c");
- final AccountType typeD = new MockAccountType("type2", "minus", "d");
-
- // Define users
- final AccountWithDataSet accountA1 = createAccountWithDataSet("a1", typeA);
- final AccountWithDataSet accountC1 = createAccountWithDataSet("c1", typeC);
- final AccountWithDataSet accountC2 = createAccountWithDataSet("c2", typeC);
- final AccountWithDataSet accountD1 = createAccountWithDataSet("d1", typeD);
-
- // empty - empty
- Map<AccountTypeWithDataSet, AccountType> types =
- AccountTypeManagerImpl.findAllInvitableAccountTypes(c,
- buildAccounts(), buildAccountTypes());
- assertEquals(0, types.size());
- try {
- types.clear();
- fail("Returned Map should be unmodifiable.");
- } catch (UnsupportedOperationException ok) {
- }
-
- // No invite support, no accounts
- verifyAccountTypes(
- buildAccounts(),
- buildAccountTypes(typeA, typeB)
- /* empty */
- );
-
- // No invite support, with accounts
- verifyAccountTypes(
- buildAccounts(accountA1),
- buildAccountTypes(typeA)
- /* empty */
- );
-
- // With invite support, no accounts
- verifyAccountTypes(
- buildAccounts(),
- buildAccountTypes(typeC)
- /* empty */
- );
-
- // With invite support, 1 account
- verifyAccountTypes(
- buildAccounts(accountC1),
- buildAccountTypes(typeC),
- typeC
- );
-
- // With invite support, 2 account
- verifyAccountTypes(
- buildAccounts(accountC1, accountC2),
- buildAccountTypes(typeC),
- typeC
- );
-
- // Combinations...
- verifyAccountTypes(
- buildAccounts(accountA1),
- buildAccountTypes(typeA, typeC)
- /* empty */
- );
-
- verifyAccountTypes(
- buildAccounts(accountC1, accountA1),
- buildAccountTypes(typeA, typeC),
- typeC
- );
-
- verifyAccountTypes(
- buildAccounts(accountC1, accountA1),
- buildAccountTypes(typeD, typeA, typeC),
- typeC
- );
-
- verifyAccountTypes(
- buildAccounts(accountC1, accountA1, accountD1),
- buildAccountTypes(typeD, typeA, typeC, typeB),
- typeC, typeD
- );
- }
-
- private static AccountWithDataSet createAccountWithDataSet(String name, AccountType type) {
- return new AccountWithDataSet(name, type.accountType, type.dataSet);
- }
-
- /**
- * Array of {@link AccountType} -> {@link Map}
- */
- private static Map<AccountTypeWithDataSet, AccountType> buildAccountTypes(AccountType... types) {
- final HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap();
- for (AccountType type : types) {
- result.put(type.getAccountTypeAndDataSet(), type);
- }
- return result;
- }
-
- /**
- * Array of {@link AccountWithDataSet} -> {@link Collection}
- */
- private static Collection<AccountWithDataSet> buildAccounts(AccountWithDataSet... accounts) {
- final List<AccountWithDataSet> result = Lists.newArrayList();
- for (AccountWithDataSet account : accounts) {
- result.add(account);
- }
- return result;
- }
-
- /**
- * Executes {@link AccountTypeManagerImpl#findInvitableAccountTypes} and verifies the
- * result.
- */
- private void verifyAccountTypes(
- Collection<AccountWithDataSet> accounts,
- Map<AccountTypeWithDataSet, AccountType> types,
- AccountType... expectedInvitableTypes
- ) {
- Map<AccountTypeWithDataSet, AccountType> result =
- AccountTypeManagerImpl.findAllInvitableAccountTypes(getContext(), accounts, types);
- for (AccountType type : expectedInvitableTypes) {
- assertTrue("Result doesn't contain type=" + type.getAccountTypeAndDataSet(),
- result.containsKey(type.getAccountTypeAndDataSet()));
- }
- final int numExcessTypes = result.size() - expectedInvitableTypes.length;
- assertEquals("Result contains " + numExcessTypes + " excess type(s)", 0, numExcessTypes);
- }
-
- private static class MockAccountType extends AccountType {
- private final String mInviteContactActivityClassName;
-
- public MockAccountType(String type, String dataSet, String inviteContactActivityClassName) {
- accountType = type;
- this.dataSet = dataSet;
- mInviteContactActivityClassName = inviteContactActivityClassName;
- }
-
- @Override
- public String getInviteContactActivityClassName() {
- return mInviteContactActivityClassName;
- }
-
- @Override
- public boolean isGroupMembershipEditable() {
- return false;
- }
-
- @Override
- public boolean areContactsWritable() {
- return false;
- }
- }
-}
diff --git a/tests/src/com/android/contacts/model/ContactLoaderTest.java b/tests/src/com/android/contacts/model/ContactLoaderTest.java
index c87ede8..60d6930 100644
--- a/tests/src/com/android/contacts/model/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/model/ContactLoaderTest.java
@@ -28,6 +28,7 @@
import android.test.LoaderTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.test.mocks.ContactsMockContext;
import com.android.contacts.common.test.mocks.MockContentProvider;
import com.android.contacts.common.model.account.AccountType;
diff --git a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
index 31eff52..3357af3 100644
--- a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
+++ b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
@@ -15,7 +15,7 @@
*/
package com.android.contacts.tests.mocks;
-import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountTypeWithDataSet;
import com.android.contacts.common.model.account.AccountWithDataSet;