diff options
author | Adnan <adnan@cyngn.com> | 2014-09-03 12:21:41 -0700 |
---|---|---|
committer | Adnan <adnan@cyngn.com> | 2014-09-03 12:21:41 -0700 |
commit | 5b1c3ec10fed8585fccb47e66ad70dbc9e8f0714 (patch) | |
tree | ef63e473015c5dec8b6c2bd58cd2715e08eadcf1 | |
parent | 7e71900b03360c0f8b86add6c2e8f1f3f1c34699 (diff) | |
download | packages_apps_Contacts-5b1c3ec10fed8585fccb47e66ad70dbc9e8f0714.tar.gz packages_apps_Contacts-5b1c3ec10fed8585fccb47e66ad70dbc9e8f0714.tar.bz2 packages_apps_Contacts-5b1c3ec10fed8585fccb47e66ad70dbc9e8f0714.zip |
Contacts: Rewrite local group edit activity.
- Tabhosts are so API level 9.
- Create contextual action bar
- Fix layouts
Change-Id: Ided714358e27b8f012d2e63837d9a0c698821bfb
-rw-r--r-- | AndroidManifest.xml | 2 | ||||
-rw-r--r-- | res/drawable-hdpi/ic_menu_content_cut.png | bin | 0 -> 1138 bytes | |||
-rw-r--r-- | res/drawable-hdpi/ic_menu_content_discard.png | bin | 0 -> 1090 bytes | |||
-rw-r--r-- | res/drawable-mdpi/ic_menu_content_cut.png | bin | 0 -> 721 bytes | |||
-rw-r--r-- | res/drawable-mdpi/ic_menu_content_discard.png | bin | 0 -> 689 bytes | |||
-rw-r--r-- | res/drawable-xhdpi/ic_menu_content_cut.png | bin | 0 -> 1565 bytes | |||
-rw-r--r-- | res/drawable-xhdpi/ic_menu_content_discard.png | bin | 0 -> 1394 bytes | |||
-rw-r--r-- | res/drawable-xxhdpi/ic_menu_content_cut.png | bin | 0 -> 2491 bytes | |||
-rw-r--r-- | res/drawable-xxhdpi/ic_menu_content_discard.png | bin | 0 -> 2162 bytes | |||
-rw-r--r-- | res/layout/group_manage.xml | 92 | ||||
-rw-r--r-- | res/layout/member_item.xml | 7 | ||||
-rw-r--r-- | res/menu/member_list_options.xml | 21 | ||||
-rw-r--r-- | res/menu/member_list_options_cab.xml | 25 | ||||
-rw-r--r-- | res/values/cm_strings.xml | 1 | ||||
-rw-r--r-- | res/xml/group_edit.xml | 47 | ||||
-rw-r--r-- | src/com/android/contacts/group/local/GroupEditActivity.java | 522 | ||||
-rw-r--r-- | src/com/android/contacts/group/local/MemberListActivity.java | 513 |
17 files changed, 484 insertions, 746 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d8e0ada58..5ffc13787 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -455,8 +455,6 @@ <activity android:name=".common.vcard.ExportVCardActivity" android:theme="@style/BackgroundOnlyTheme" /> - <activity android:name=".group.local.GroupEditActivity" /> - <activity android:name=".group.local.MemberListActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.Holo.Light"> diff --git a/res/drawable-hdpi/ic_menu_content_cut.png b/res/drawable-hdpi/ic_menu_content_cut.png Binary files differnew file mode 100644 index 000000000..58b5e49af --- /dev/null +++ b/res/drawable-hdpi/ic_menu_content_cut.png diff --git a/res/drawable-hdpi/ic_menu_content_discard.png b/res/drawable-hdpi/ic_menu_content_discard.png Binary files differnew file mode 100644 index 000000000..ece5ad8d6 --- /dev/null +++ b/res/drawable-hdpi/ic_menu_content_discard.png diff --git a/res/drawable-mdpi/ic_menu_content_cut.png b/res/drawable-mdpi/ic_menu_content_cut.png Binary files differnew file mode 100644 index 000000000..91f267d8b --- /dev/null +++ b/res/drawable-mdpi/ic_menu_content_cut.png diff --git a/res/drawable-mdpi/ic_menu_content_discard.png b/res/drawable-mdpi/ic_menu_content_discard.png Binary files differnew file mode 100644 index 000000000..93483b6cb --- /dev/null +++ b/res/drawable-mdpi/ic_menu_content_discard.png diff --git a/res/drawable-xhdpi/ic_menu_content_cut.png b/res/drawable-xhdpi/ic_menu_content_cut.png Binary files differnew file mode 100644 index 000000000..5885fcf94 --- /dev/null +++ b/res/drawable-xhdpi/ic_menu_content_cut.png diff --git a/res/drawable-xhdpi/ic_menu_content_discard.png b/res/drawable-xhdpi/ic_menu_content_discard.png Binary files differnew file mode 100644 index 000000000..94f7c8c1c --- /dev/null +++ b/res/drawable-xhdpi/ic_menu_content_discard.png diff --git a/res/drawable-xxhdpi/ic_menu_content_cut.png b/res/drawable-xxhdpi/ic_menu_content_cut.png Binary files differnew file mode 100644 index 000000000..dd5c2a38f --- /dev/null +++ b/res/drawable-xxhdpi/ic_menu_content_cut.png diff --git a/res/drawable-xxhdpi/ic_menu_content_discard.png b/res/drawable-xxhdpi/ic_menu_content_discard.png Binary files differnew file mode 100644 index 000000000..df7526973 --- /dev/null +++ b/res/drawable-xxhdpi/ic_menu_content_discard.png diff --git a/res/layout/group_manage.xml b/res/layout/group_manage.xml index 150b403c4..a5e720ced 100644 --- a/res/layout/group_manage.xml +++ b/res/layout/group_manage.xml @@ -29,80 +29,34 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> <TabHost - android:id="@android:id/tabhost" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - xmlns:android="http://schemas.android.com/apk/res/android"> + android:id="@android:id/tabhost" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> - <FrameLayout - android:id="@android:id/tabcontent" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_weight="0" /> - - <TabWidget - android:id="@android:id/tabs" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:visibility="gone" /> - - <TextView android:id="@+id/emptyText" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:text="@string/noMember" - android:textSize="20sp" - android:textColor="?android:attr/textColorSecondary" - android:paddingLeft="10dip" - android:paddingRight="10dip" - android:paddingTop="10dip" - android:gravity="center" - android:lineSpacingMultiplier="0.92"/> - - <ListView - android:layout_weight="1" - android:id="@+id/member_list" - android:visibility="gone" - android:layout_width="fill_parent" - android:layout_height="wrap_content" /> - - <LinearLayout android:id="@+id/tool_bar" - android:layout_weight="0" - android:orientation="horizontal" - android:visibility="gone" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingTop="5dip" - android:paddingLeft="4dip" - android:paddingRight="4dip" - android:paddingBottom="1dip" - android:background="@android:drawable/bottom_bar"> - - <Button - android:id="@+id/btn_delete" - android:layout_width="0dip" - android:layout_height="match_parent" - android:layout_weight="1" - android:text="@string/button_delete" /> - - <Button - android:id="@+id/btn_move" - android:layout_width="0dip" - android:layout_height="match_parent" - android:layout_weight="1" - android:text="@string/button_moveto" /> - - <Button - android:id="@+id/btn_cancel" - android:layout_width="0dip" - android:layout_height="match_parent" - android:layout_weight="1" - android:text="@string/button_cancel" /> - </LinearLayout> + <TextView android:id="@+id/emptyText" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:text="@string/noMember" + android:textSize="20sp" + android:textColor="?android:attr/textColorSecondary" + android:paddingLeft="10dip" + android:paddingRight="10dip" + android:paddingTop="10dip" + android:gravity="center" + android:lineSpacingMultiplier="0.92"/> + + <ListView + android:layout_weight="1" + android:id="@+id/member_list" + android:visibility="gone" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> </LinearLayout> </TabHost> diff --git a/res/layout/member_item.xml b/res/layout/member_item.xml index 04c9d7e63..0ac8239a9 100644 --- a/res/layout/member_item.xml +++ b/res/layout/member_item.xml @@ -43,8 +43,8 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:layout_weight="1" - android:paddingLeft="3dip" - android:paddingRight="3dip"> + android:paddingLeft="5dip" + android:paddingRight="5dip"> <QuickContactBadge android:layout_width="48dip" android:layout_height="48dip" @@ -54,7 +54,8 @@ <TextView android:layout_weight="1" - android:gravity="right" + android:gravity="left" + android:paddingLeft="3dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" diff --git a/res/menu/member_list_options.xml b/res/menu/member_list_options.xml new file mode 100644 index 000000000..0992da3df --- /dev/null +++ b/res/menu/member_list_options.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The CyanogenMod 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. +--> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/add" + android:icon="@drawable/ic_menu_add_field_holo_light" + android:title="@string/title_add_members" + android:showAsAction="always" /> +</menu>
\ No newline at end of file diff --git a/res/menu/member_list_options_cab.xml b/res/menu/member_list_options_cab.xml new file mode 100644 index 000000000..9c41e4e3c --- /dev/null +++ b/res/menu/member_list_options_cab.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The CyanogenMod 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. +--> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/move" + android:icon="@drawable/ic_menu_content_cut" + android:title="@string/button_moveto" + android:showAsAction="always" /> + <item android:id="@+id/remove" + android:icon="@drawable/ic_menu_content_discard" + android:title="@string/button_delete" + android:showAsAction="always" /> +</menu>
\ No newline at end of file diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 2ffcde95b..bba1b247b 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -215,6 +215,7 @@ <string name="menu_sync_to_baidu_cloud">Sync to Baidu Cloud Now</string> <string name="delete_locale_group_dialog_message">Confirm group deletion?</string> + <string name="edit_local_group_dialog_title">Rename group</string> <string name="too_many_contacts_add_to_group">Too many contacts, must be fewer than <xliff:g id="count">%d</xliff:g></string> diff --git a/res/xml/group_edit.xml b/res/xml/group_edit.xml deleted file mode 100644 index 239924b47..000000000 --- a/res/xml/group_edit.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * - * Copyright (c) 2013, The Linux Foundation. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --> -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - android:title="@string/title_group_edit"> - <EditTextPreference - android:key="group_title" - android:dialogTitle="@string/title_group_name" - android:persistent="false" - android:summary="@string/title_group_name"/> - - <PreferenceScreen - android:key="group_member" - android:title="@string/title_add_members" - android:summary="@string/summary_add_members" - android:persistent="false" /> - - <PreferenceCategory - android:title="@string/title_members_list"/> -</PreferenceScreen> diff --git a/src/com/android/contacts/group/local/GroupEditActivity.java b/src/com/android/contacts/group/local/GroupEditActivity.java deleted file mode 100644 index c3164c797..000000000 --- a/src/com/android/contacts/group/local/GroupEditActivity.java +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright (C) 2013,The Linux Foundation. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.android.contacts.group.local; - -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.ProgressDialog; -import android.content.ContentProviderOperation; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.database.Cursor; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Message; -import android.preference.EditTextPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceActivity; -import android.preference.PreferenceScreen; -import android.provider.ContactsContract; -import android.provider.LocalGroups; -import android.provider.ContactsContract.CommonDataKinds.LocalGroup; -import android.provider.ContactsContract.Data; -import android.provider.ContactsContract.RawContacts; -import android.provider.LocalGroups.Group; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.widget.Toast; - -import com.android.contacts.R; -import com.android.contacts.editor.MultiPickContactActivity; -import com.android.contacts.common.list.AccountFilterActivity; -import com.android.contacts.common.list.ContactListFilter; -import com.android.contacts.common.SimContactsConstants; -import com.android.contacts.common.model.account.PhoneAccountType; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Set; - -public class GroupEditActivity extends PreferenceActivity implements OnPreferenceChangeListener, - OnPreferenceClickListener, TextWatcher { - - private static final String TAG = GroupEditActivity.class.getSimpleName(); - - private static final String KEY_TITLE = "group_title"; - - private static final String KEY_MEMBER = "group_member"; - - private EditTextPreference titleView; - - private Group group; - - private PreferenceScreen addMemberView; - - private static final int CODE_PICK_MEMBER = 1; - private AddMembersTask mAddMembersTask; - - // indicate whether the task is canceled. - private boolean mIsAddMembersTaskCanceled; - - private static final int MSG_CANCEL = 1; - - private int mChangeStartPos; - private int mChangeCount; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - this.addPreferencesFromResource(R.xml.group_edit); - titleView = (EditTextPreference) this.findPreference(KEY_TITLE); - titleView.getEditText().addTextChangedListener(this); - titleView.setOnPreferenceChangeListener(this); - addMemberView = (PreferenceScreen) this.findPreference(KEY_MEMBER); - addMemberView.setOnPreferenceClickListener(this); - } - - @Override - protected void onResume() { - super.onResume(); - group = Group.restoreGroupById(getContentResolver(), - Long.parseLong(getIntent().getData().getLastPathSegment())); - initView(); - } - - private void initView() { - // avoid group is null, only for Monkey test. - if (group != null) { - // If the length of group name is more than GROUP_NAME_MAX_LENGTH, - // the - // name will be limited here. - String groupName = group.getTitle(); - if (groupName.length() > AddLocalGroupDialog.GROUP_NAME_MAX_LENGTH) { - groupName = groupName.substring(0, AddLocalGroupDialog.GROUP_NAME_MAX_LENGTH); - } - titleView.setTitle(groupName); - titleView.setText(groupName); - } - } - - @Override - public boolean onPreferenceChange(Preference arg0, Object arg1) { - if (titleView == arg0 && !group.getTitle().equals(arg1) && ((String) arg1).length() > 0) { - if (checkGroupTitleExist((String) arg1)) { - Toast.makeText(getApplicationContext(), R.string.error_group_exist, - Toast.LENGTH_SHORT).show(); - } else { - group.setTitle((String) arg1); - if (group.update(getContentResolver())) - initView(); - } - } - return false; - } - - private boolean checkGroupTitleExist(String name) { - Cursor c = null; - try { - c = getApplicationContext().getContentResolver().query( - LocalGroups.CONTENT_URI, null, LocalGroups.GroupColumns.TITLE + "=?", - new String[] { - name - }, null); - if (c != null) { - return c.getCount() > 0; - } else { - return false; - } - } finally { - if (c != null) { - c.close(); - } - } - } - - @Override - public boolean onPreferenceClick(Preference preference) { - if (addMemberView == preference) { - pickMembers(); - } - return false; - } - - private void pickMembers() { - Intent intent = new Intent(MultiPickContactActivity.ACTION_MULTI_PICK); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); - intent.putExtra(MultiPickContactActivity.IS_CONTACT,true); - intent.setClass(this, MultiPickContactActivity.class); - ContactListFilter filter = new ContactListFilter(ContactListFilter.FILTER_TYPE_ACCOUNT, - PhoneAccountType.ACCOUNT_TYPE, SimContactsConstants.PHONE_NAME, null, null); - intent.putExtra(AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER, filter); - startActivityForResult(intent, CODE_PICK_MEMBER); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, 0, 0, R.string.menu_option_delete); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case 0: - new AlertDialog.Builder(this) - .setMessage(R.string.delete_locale_group_dialog_message) - .setTitle(R.string.delete_group_dialog_title) - .setIcon(android.R.drawable.ic_dialog_alert) - .setPositiveButton(R.string.btn_ok, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - // TODO Auto-generated method stub - if (group.delete(getContentResolver())) { - finish(); - } - } - }).setNegativeButton(R.string.btn_cancel, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - // TODO Auto-generated method stub - // Don't need any operation - } - }).show(); - - break; - } - return super.onOptionsItemSelected(item); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) - switch (requestCode) { - case CODE_PICK_MEMBER: - Bundle result = data.getExtras().getBundle("result"); - - // define member object mAddMembersTask to use later. - mAddMembersTask = new AddMembersTask(result); - mAddMembersTask.execute(); - } - } - - class AddMembersTask extends AsyncTask<Object, Object, Object> { - private ProgressDialog mProgressDialog; - - private Handler alertHandler = new Handler() { - @Override - public void dispatchMessage(Message msg) { - if (msg.what == MSG_CANCEL) { - Toast.makeText(GroupEditActivity.this, R.string.add_member_task_canceled, - Toast.LENGTH_LONG).show(); - } else if (msg.what == 0) { - Toast.makeText(GroupEditActivity.this, R.string.toast_not_add, - Toast.LENGTH_LONG) - .show(); - } - } - }; - - private Bundle result; - - private int size; - - AddMembersTask(Bundle result) { - size = result.size(); - this.result = result; - HandlerThread thread = new HandlerThread("DownloadTask"); - thread.start(); - } - - protected void onPostExecute(Object result) { - if (mProgressDialog != null && mProgressDialog.isShowing()) { - mProgressDialog.dismiss(); - } - new LocalGroupCountTask(GroupEditActivity.this).execute(); - } - - @Override - protected void onPreExecute() { - mIsAddMembersTaskCanceled = false; - mProgressDialog = new ProgressDialog(GroupEditActivity.this); - mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - mProgressDialog.setProgress(0); - mProgressDialog.setMax(size); - mProgressDialog.show(); - mProgressDialog.setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - - // if dialog is canceled, cancel the task also. - mIsAddMembersTaskCanceled = true; - } - }); - } - - @Override - protected Bundle doInBackground(Object... params) { - proccess(); - return null; - } - - public void proccess() { - boolean hasInvalide = false; - int progressIncrement = 0; - ContentValues values = new ContentValues(); - // add Non-null protection of group for monkey test - if (null != group) { - values.put(LocalGroup.DATA1, group.getId()); - } - - Set<String> keySet = result.keySet(); - Iterator<String> it = keySet.iterator(); - - // add a ContentProviderOperation update list. - final ArrayList<ContentProviderOperation> updateList = - new ArrayList<ContentProviderOperation>(); - ContentProviderOperation.Builder builder = null; - mIsAddMembersTaskCanceled = false; - while (it.hasNext()) { - if (mIsAddMembersTaskCanceled) { - alertHandler.sendEmptyMessage(MSG_CANCEL); - break; - } - if (progressIncrement++ % 2 == 0) { - if (mProgressDialog != null) { - mProgressDialog.incrementProgressBy(2); - } else if (mProgressDialog != null && mProgressDialog.isShowing()) { - mProgressDialog.dismiss(); - mProgressDialog = null; - } - } - String id = it.next(); - Cursor c = null; - try { - c = getContentResolver().query(RawContacts.CONTENT_URI, new String[] { - RawContacts._ID, RawContacts.ACCOUNT_TYPE - }, RawContacts.CONTACT_ID + "=?", new String[] { - id - }, null); - if (c.moveToNext()) { - String rawId = String.valueOf(c.getLong(0)); - - if (!PhoneAccountType.ACCOUNT_TYPE.equals(c.getString(1))) { - hasInvalide = true; - continue; - } - - builder = ContentProviderOperation.newDelete(Data.CONTENT_URI); - builder.withSelection(Data.RAW_CONTACT_ID + "=? and " + Data.MIMETYPE - + "=?", new String[] { - rawId, LocalGroup.CONTENT_ITEM_TYPE - }); - - // add the delete operation to the update list. - updateList.add(builder.build()); - - builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); - // add Non-null protection of group for monkey test - if (null != group) { - builder.withValue(LocalGroup.DATA1, group.getId()); - } - builder.withValue(Data.RAW_CONTACT_ID, rawId); - builder.withValue(Data.MIMETYPE, LocalGroup.CONTENT_ITEM_TYPE); - - // add the insert operation to the update list. - updateList.add(builder.build()); - } - } finally { - if (c != null) { - c.close(); - } - } - } - - // if task is canceled ,still update the database with the data in - // updateList. - - // apply batch to execute the delete and insert operation. - if (updateList.size() > 0) { - addMembersApplyBatchByBuffer(updateList, getContentResolver()); - } - if (hasInvalide) { - alertHandler.sendEmptyMessage(0); - } - } - - private void addMembersApplyBatchByBuffer(ArrayList<ContentProviderOperation> list, - ContentResolver cr) { - final ArrayList<ContentProviderOperation> temp = - new ArrayList<ContentProviderOperation>(BUFFER_LENGTH); - int bufferSize = list.size() / BUFFER_LENGTH; - for (int index = 0; index <= bufferSize; index++) { - temp.clear(); - if (index == bufferSize) { - for (int i = index * BUFFER_LENGTH; i < list.size(); i++) { - temp.add(list.get(i)); - } - } else { - for (int i = index * BUFFER_LENGTH; i < index * BUFFER_LENGTH + BUFFER_LENGTH; - i++) { - temp.add(list.get(i)); - } - } - if (!temp.isEmpty()) { - try { - cr.applyBatch(ContactsContract.AUTHORITY, temp); - if (mProgressDialog != null) { - mProgressDialog.incrementProgressBy(temp.size() / 4); - } else if (mProgressDialog != null && mProgressDialog.isShowing()) { - mProgressDialog.dismiss(); - mProgressDialog = null; - } - } catch (Exception e) { - Log.e(TAG, "apply batch by buffer error:" + e); - } - } - } - } - } - - /** - * the max length of applyBatch is 500 - */ - private static final int BUFFER_LENGTH = 499; - - public static void applyBatchByBuffer(ArrayList<ContentProviderOperation> list, - ContentResolver cr) { - final ArrayList<ContentProviderOperation> temp = new ArrayList<ContentProviderOperation>( - BUFFER_LENGTH); - int bufferSize = list.size() / BUFFER_LENGTH; - for (int index = 0; index <= bufferSize; index++) { - temp.clear(); - if (index == bufferSize) { - for (int i = index * BUFFER_LENGTH; i < list.size(); i++) { - temp.add(list.get(i)); - } - } else { - for (int i = index * BUFFER_LENGTH; i < index * BUFFER_LENGTH + BUFFER_LENGTH; - i++) { - temp.add(list.get(i)); - } - } - if (!temp.isEmpty()) { - try { - cr.applyBatch(ContactsContract.AUTHORITY, temp); - } catch (Exception e) { - Log.e(TAG, "apply batch by buffer error:" + e); - } - } - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // TODO Auto-generated method stub - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - // The start position of new added characters. - mChangeStartPos = start; - // The number of new added characters. - mChangeCount = count; - } - - @Override - public void afterTextChanged(Editable s) { - String name = s.toString(); - int len = 0; - // The end position of insert string. - int insertEnd = mChangeStartPos + mChangeCount - 1; - // The string need to keep. - String keepStr = name.substring(insertEnd + 1); - // Keep string len. - int keepStrCharLen = 0; - for (int n = 0; n < keepStr.length(); n++) { - // Get the char length of keep string. - // To get the char number need insert. - keepStrCharLen += getCharacterVisualLength(keepStr, n); - } - String headStr = name.substring(0, insertEnd + 1); - for (int i = 0; i < headStr.length(); i++) { - int ch = Character.codePointAt(name, i); - len += getCharacterVisualLength(name, i); - if (len > AddLocalGroupDialog.GROUP_NAME_MAX_LENGTH - keepStrCharLen || ch == 10) { - // Delete the redundant text. - s.delete(i, s.length() - keepStr.length()); - // Use setTextKeepState to keep the cursor position. - titleView.getEditText().setTextKeepState(s); - break; - } - } - } - - /** - * A character beyond 0xff is twice as big as a character within 0xff in - * width when showing. - */ - private int getCharacterVisualLength(String seq, int index) { - int cp = Character.codePointAt(seq, index); - if (cp >= 0x00 && cp <= 0xFF) { - return 1; - } else { - return 2; - } - } - - @Override - protected void onStop() { - - // dismiss dialog and cancel the task in order to avoid a case that - // GroupEditActivity does - // not exist,but task is going on in background, then onPostExecute() - // will cause Exception. - if (mAddMembersTask != null && mAddMembersTask.mProgressDialog != null) { - if (mAddMembersTask.mProgressDialog.isShowing()) { - mAddMembersTask.mProgressDialog.dismiss(); - mIsAddMembersTaskCanceled = true; - } - } - super.onStop(); - } -} diff --git a/src/com/android/contacts/group/local/MemberListActivity.java b/src/com/android/contacts/group/local/MemberListActivity.java index 711cd3f40..41b012f17 100644 --- a/src/com/android/contacts/group/local/MemberListActivity.java +++ b/src/com/android/contacts/group/local/MemberListActivity.java @@ -29,11 +29,14 @@ package com.android.contacts.group.local; +import android.app.ActionBar; +import android.app.Activity; import android.app.AlertDialog; -import android.app.TabActivity; +import android.app.ProgressDialog; import android.content.AsyncQueryHandler; import android.content.ContentProviderOperation; import android.content.ContentResolver; +import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; @@ -48,8 +51,10 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerThread; import android.os.Message; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds.LocalGroup; @@ -58,39 +63,43 @@ import android.provider.ContactsContract.Contacts.Photo; import android.provider.ContactsContract.Data; import android.provider.LocalGroups; import android.provider.LocalGroups.GroupColumns; +import android.text.TextUtils; import android.util.Log; +import android.view.ActionMode; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.view.animation.AnimationUtils; +import android.widget.AbsListView; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.Button; import android.widget.CheckBox; import android.widget.CursorAdapter; +import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.QuickContactBadge; -import android.widget.TabHost; import android.widget.TextView; +import android.widget.Toast; import com.android.contacts.R; import com.android.contacts.common.ContactPhotoManager; import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; +import com.android.contacts.common.SimContactsConstants; +import com.android.contacts.common.list.AccountFilterActivity; +import com.android.contacts.common.list.ContactListFilter; +import com.android.contacts.common.model.account.PhoneAccountType; +import com.android.contacts.editor.MultiPickContactActivity; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; -public class MemberListActivity extends TabActivity implements OnItemClickListener, - OnClickListener, OnItemLongClickListener { +public class MemberListActivity extends Activity implements AdapterView.OnItemClickListener { - private static final String TAB_TAG = "groups"; - - private TabHost mTabHost; + private static final int CODE_PICK_MEMBER = 1; private Uri uri; @@ -119,19 +128,16 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen private MemberListAdapter mAdapter; - private ListView listView; - - private TextView emptyText; - - private Bundle removeSet; + private AddMembersTask mAddMembersTask; + private LocalGroups.Group mGroup; - private View toolsBar; + private ActionMode mActionMode; - private Button deleteBtn; + private ListView mListView; - private Button moveBtn; + private TextView emptyText; - private Button cancelBtn; + private Bundle mRemoveSet; private DeleteMembersThread mDeleteMembersTask; @@ -143,7 +149,7 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen @Override public void handleMessage(Message msg) { mDeleteMembersTask = null; - removeSet.clear(); + mRemoveSet.clear(); mAdapter.refresh(); new LocalGroupCountTask(MemberListActivity.this).execute(); } @@ -165,7 +171,7 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen this.mRemoveSet = removeSet; } - public int getStaus() { + public int getStatus() { return status; } @@ -259,29 +265,103 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen super.onCreate(savedInstanceState); setContentView(R.layout.group_manage); - toolsBar = findViewById(R.id.tool_bar); - deleteBtn = (Button) toolsBar.findViewById(R.id.btn_delete); - moveBtn = (Button) toolsBar.findViewById(R.id.btn_move); - cancelBtn = (Button) toolsBar.findViewById(R.id.btn_cancel); - deleteBtn.setOnClickListener(this); - moveBtn.setOnClickListener(this); - cancelBtn.setOnClickListener(this); + // actionbar setup + final ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); - removeSet = new Bundle(); + mRemoveSet = new Bundle(); mQueryHandler = new QueryHandler(this); mAdapter = new MemberListAdapter(this); mContactPhotoManager = ContactPhotoManager.getInstance(this); emptyText = (TextView) findViewById(R.id.emptyText); - listView = (ListView) findViewById(R.id.member_list); - listView.setOnItemClickListener(this); - listView.setOnItemLongClickListener(this); - listView.setAdapter(mAdapter); - mTabHost = getTabHost(); + mListView = (ListView) findViewById(R.id.member_list); + mListView.setAdapter(mAdapter); + mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); + mListView.setOnItemClickListener(this); + mListView.setMultiChoiceModeListener(mMultiChoiceModeListener); uri = getIntent().getParcelableExtra("data"); - addEditView(); getContentResolver().registerContentObserver( Uri.withAppendedPath(LocalGroup.CONTENT_FILTER_URI, Uri.encode(uri.getLastPathSegment())), true, observer); + mGroup = LocalGroups.Group.restoreGroupById(getContentResolver(), + Long.parseLong(uri.getLastPathSegment())); + actionBar.setSubtitle(mGroup.getTitle()); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.member_list_options, menu); + menu.add(0, 0, 0, R.string.menu_option_delete); + menu.add(0, 1, 0, R.string.edit_local_group_dialog_title); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + case R.id.add: + pickMembers(); + break; + case 0: + new AlertDialog.Builder(this) + .setMessage(R.string.delete_locale_group_dialog_message) + .setTitle(R.string.delete_group_dialog_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // TODO Auto-generated method stub + if (mGroup.delete(getContentResolver())) { + finish(); + } + } + }).setNegativeButton(R.string.btn_cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + // TODO Auto-generated method stub + // Don't need any operation + } + }).show(); + break; + case 1: + final EditText editText = new EditText(this); + editText.setHint(R.string.group_edit_field_hint_text); + new AlertDialog.Builder(this) + .setTitle(R.string.edit_local_group_dialog_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setView(editText) + .setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (!TextUtils.isEmpty(editText.getText())) { + if (checkGroupTitleExist(editText.getText().toString())) { + Toast.makeText(getApplicationContext(), R.string.error_group_exist, + Toast.LENGTH_SHORT).show(); + } else { + mGroup.setTitle(editText.getText().toString()); + if (mGroup.update(getContentResolver())) { + getActionBar().setSubtitle(mGroup.getTitle()); + } + } + } + } + }).setNegativeButton(R.string.btn_cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + // TODO Auto-generated method stub + // Don't need any operation + } + }).show(); + } + return false; } private ContentObserver observer = new ContentObserver(new Handler()) { @@ -291,6 +371,26 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen } }; + private boolean checkGroupTitleExist(String name) { + Cursor c = null; + try { + c = getApplicationContext().getContentResolver().query( + LocalGroups.CONTENT_URI, null, LocalGroups.GroupColumns.TITLE + "=?", + new String[] { + name + }, null); + if (c != null) { + return c.getCount() > 0; + } else { + return false; + } + } finally { + if (c != null) { + c.close(); + } + } + } + @Override protected void onPause() { super.onPause(); @@ -304,35 +404,67 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen getContentResolver().unregisterContentObserver(observer); } - @Override - public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { - selectAll(); - return true; - } - private void updateDisplay(boolean isEmpty) { if (isEmpty) { - listView.setVisibility(View.GONE); + mListView.setVisibility(View.GONE); emptyText.setVisibility(View.VISIBLE); } else { - listView.setVisibility(View.VISIBLE); + mListView.setVisibility(View.VISIBLE); emptyText.setVisibility(View.GONE); } } - private void selectAll() { - Cursor cursor = mAdapter.getCursor(); - if (cursor == null) { - return; + private AbsListView.MultiChoiceModeListener mMultiChoiceModeListener + = new AbsListView.MultiChoiceModeListener() { + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, + long id, boolean checked) { + View v = mListView.getChildAt(position); + String contactId = (String) v.getTag(); + CheckBox checkBox = (CheckBox) v.findViewById(R.id.pick_contact_check); + if (mRemoveSet.containsKey(contactId)) { + mRemoveSet.remove(contactId); + } else { + mRemoveSet.putString(contactId, contactId); + } + setCheckStatus(contactId, checkBox); } - cursor.moveToPosition(-1); - while (cursor.moveToNext()) { - String contactId = String.valueOf(cursor.getLong(SUMMARY_RAW_CONTACTS_ID_INDEX)); - removeSet.putString(contactId, contactId); + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + mode.getMenuInflater().inflate(R.menu.member_list_options_cab, menu); + mActionMode = mode; + return true; } - mAdapter.refresh(); - } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.id.move: + chooseGroup(); + return true; + case R.id.remove: + removeContactsFromGroup(); + mAdapter.refresh(); + return true; + } + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + mListView.clearChoices(); + mRemoveSet.clear(); + mAdapter.notifyDataSetChanged(); + mActionMode = null; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + }; @Override protected void onResume() { @@ -341,13 +473,17 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen startQuery(); } - private void addEditView() { - Intent intent = new Intent(this, GroupEditActivity.class); - intent.setData(uri); - - mTabHost.addTab(mTabHost.newTabSpec(TAB_TAG) - .setIndicator(TAB_TAG, getResources().getDrawable(R.drawable.ic_launcher_contacts)) - .setContent(intent)); + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK) + switch (requestCode) { + case CODE_PICK_MEMBER: + Bundle result = data.getExtras().getBundle("result"); + + // define member object mAddMembersTask to use later. + mAddMembersTask = new AddMembersTask(result); + mAddMembersTask.execute(); + } } private void startQuery() { @@ -423,18 +559,18 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen * job if removeSet is empty. */ Cursor cursor = getCursor(); - if (!removeSet.isEmpty() && cursor != null && !cursor.isClosed()) { + if (!mRemoveSet.isEmpty() && cursor != null && !cursor.isClosed()) { cursor.moveToPosition(-1); Bundle newRemoveSet = new Bundle(); while (cursor.moveToNext()) { String contactId = String.valueOf( cursor.getLong(SUMMARY_RAW_CONTACTS_ID_INDEX)); - if (removeSet.containsKey(contactId)) { + if (mRemoveSet.containsKey(contactId)) { newRemoveSet.putString(contactId, contactId); } } - if (newRemoveSet.size() != removeSet.size()) { - removeSet = newRemoveSet; + if (newRemoveSet.size() != mRemoveSet.size()) { + mRemoveSet = newRemoveSet; } } updateToolsBar(); @@ -517,52 +653,38 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen } @Override - public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { - String contactId = (String) arg1.getTag(); - CheckBox checkBox = (CheckBox) arg1.findViewById(R.id.pick_contact_check); - if (removeSet.containsKey(contactId)) { - removeSet.remove(contactId); + public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { + if (!mListView.isItemChecked(position)) { + mListView.setItemChecked(position, true); } else { - removeSet.putString(contactId, contactId); + mListView.setItemChecked(position, false); } - setCheckStatus(contactId, checkBox); - updateToolsBar(); + } + + private void pickMembers() { + Intent intent = new Intent(MultiPickContactActivity.ACTION_MULTI_PICK); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); + intent.putExtra(MultiPickContactActivity.IS_CONTACT,true); + intent.setClass(this, MultiPickContactActivity.class); + ContactListFilter filter = new ContactListFilter(ContactListFilter.FILTER_TYPE_ACCOUNT, + PhoneAccountType.ACCOUNT_TYPE, SimContactsConstants.PHONE_NAME, null, null); + intent.putExtra(AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER, filter); + startActivityForResult(intent, CODE_PICK_MEMBER); } private void updateToolsBar() { if (mDeleteMembersTask != null - && mDeleteMembersTask.getStaus() == DeleteMembersThread.TASK_RUNNING) { - if (toolsBar.getVisibility() != View.GONE) { - toolsBar.setVisibility(View.GONE); - } + && mDeleteMembersTask.getStatus() == DeleteMembersThread.TASK_RUNNING) { return; } - if (removeSet.isEmpty() && toolsBar.getVisibility() == View.VISIBLE) { - toolsBar.setVisibility(View.GONE); - toolsBar.startAnimation(AnimationUtils.loadAnimation(this, R.anim.tools_bar_disappear)); - } else if (!removeSet.isEmpty() && toolsBar.getVisibility() == View.GONE) { - toolsBar.setVisibility(View.VISIBLE); - toolsBar.startAnimation(AnimationUtils.loadAnimation(this, R.anim.tools_bar_appear)); + if (mRemoveSet.isEmpty() && mActionMode != null) { + mActionMode.finish(); } } private void setCheckStatus(String contactId, CheckBox checkBox) { - checkBox.setChecked(removeSet.containsKey(contactId)); - } - - @Override - public void onClick(View v) { - if (v == cancelBtn) { - removeSet.clear(); - mAdapter.refresh(); - } else if (v == deleteBtn) { - removeContactsFromGroup(); - mAdapter.refresh(); - } else if (v == moveBtn) { - chooseGroup(); - } - + checkBox.setChecked(mRemoveSet.containsKey(contactId)); } private void chooseGroup() { @@ -601,8 +723,8 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen } private void moveContactstoGroup(int groupId) { - if (removeSet != null && removeSet.size() > 0) { - Bundle bundleData = (Bundle) removeSet.clone(); + if (mRemoveSet != null && mRemoveSet.size() > 0) { + Bundle bundleData = (Bundle) mRemoveSet.clone(); if (mDeleteMembersTask != null) { mDeleteMembersTask.setStatus(DeleteMembersThread.TASK_CANCEL); mDeleteMembersTask = null; @@ -615,8 +737,8 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen } private void removeContactsFromGroup() { - if (removeSet != null && removeSet.size() > 0) { - Bundle bundleData = (Bundle) removeSet.clone(); + if (mRemoveSet != null && mRemoveSet.size() > 0) { + Bundle bundleData = (Bundle) mRemoveSet.clone(); if (mDeleteMembersTask != null) { mDeleteMembersTask.setStatus(DeleteMembersThread.TASK_CANCEL); mDeleteMembersTask = null; @@ -651,4 +773,189 @@ public class MemberListActivity extends TabActivity implements OnItemClickListen return new DefaultImageRequest(displayName, lookupKey); } + + class AddMembersTask extends AsyncTask<Object, Object, Object> { + private ProgressDialog mProgressDialog; + private static final int MSG_CANCEL = 1; + private boolean mIsAddMembersTaskCanceled; + + private Handler alertHandler = new Handler() { + @Override + public void dispatchMessage(Message msg) { + if (msg.what == MSG_CANCEL) { + Toast.makeText(MemberListActivity.this, R.string.add_member_task_canceled, + Toast.LENGTH_LONG).show(); + } else if (msg.what == 0) { + Toast.makeText(MemberListActivity.this, R.string.toast_not_add, + Toast.LENGTH_LONG) + .show(); + } + } + }; + + private Bundle result; + + private int size; + + AddMembersTask(Bundle result) { + size = result.size(); + this.result = result; + HandlerThread thread = new HandlerThread("DownloadTask"); + thread.start(); + } + + protected void onPostExecute(Object result) { + if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + } + new LocalGroupCountTask(MemberListActivity.this).execute(); + } + + @Override + protected void onPreExecute() { + mIsAddMembersTaskCanceled = false; + mProgressDialog = new ProgressDialog(MemberListActivity.this); + mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + mProgressDialog.setProgress(0); + mProgressDialog.setMax(size); + mProgressDialog.show(); + mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + + // if dialog is canceled, cancel the task also. + mIsAddMembersTaskCanceled = true; + } + }); + } + + @Override + protected Bundle doInBackground(Object... params) { + process(); + return null; + } + + public void process() { + boolean hasInvalide = false; + int progressIncrement = 0; + ContentValues values = new ContentValues(); + // add Non-null protection of group for monkey test + if (null != mGroup) { + values.put(LocalGroup.DATA1, mGroup.getId()); + } + + Set<String> keySet = result.keySet(); + Iterator<String> it = keySet.iterator(); + + // add a ContentProviderOperation update list. + final ArrayList<ContentProviderOperation> updateList = + new ArrayList<ContentProviderOperation>(); + ContentProviderOperation.Builder builder = null; + mIsAddMembersTaskCanceled = false; + while (it.hasNext()) { + if (mIsAddMembersTaskCanceled) { + alertHandler.sendEmptyMessage(MSG_CANCEL); + break; + } + if (progressIncrement++ % 2 == 0) { + if (mProgressDialog != null) { + mProgressDialog.incrementProgressBy(2); + } else if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } + } + String id = it.next(); + Cursor c = null; + try { + c = getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, new String[] { + ContactsContract.RawContacts._ID, ContactsContract.RawContacts.ACCOUNT_TYPE + }, ContactsContract.RawContacts.CONTACT_ID + "=?", new String[] { + id + }, null); + if (c.moveToNext()) { + String rawId = String.valueOf(c.getLong(0)); + + if (!PhoneAccountType.ACCOUNT_TYPE.equals(c.getString(1))) { + hasInvalide = true; + continue; + } + + builder = ContentProviderOperation.newDelete(Data.CONTENT_URI); + builder.withSelection(Data.RAW_CONTACT_ID + "=? and " + Data.MIMETYPE + + "=?", new String[] { + rawId, LocalGroup.CONTENT_ITEM_TYPE + }); + + // add the delete operation to the update list. + updateList.add(builder.build()); + + builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); + // add Non-null protection of group for monkey test + if (null != mGroup) { + builder.withValue(LocalGroup.DATA1, mGroup.getId()); + } + builder.withValue(Data.RAW_CONTACT_ID, rawId); + builder.withValue(Data.MIMETYPE, LocalGroup.CONTENT_ITEM_TYPE); + + // add the insert operation to the update list. + updateList.add(builder.build()); + } + } finally { + if (c != null) { + c.close(); + } + } + } + + // if task is canceled ,still update the database with the data in + // updateList. + + // apply batch to execute the delete and insert operation. + if (updateList.size() > 0) { + addMembersApplyBatchByBuffer(updateList, getContentResolver()); + } + if (hasInvalide) { + alertHandler.sendEmptyMessage(0); + } + } + + /** + * the max length of applyBatch is 500 + */ + private static final int BUFFER_LENGTH = 499; + + + private void addMembersApplyBatchByBuffer(ArrayList<ContentProviderOperation> list, + ContentResolver cr) { + final ArrayList<ContentProviderOperation> temp = + new ArrayList<ContentProviderOperation>(BUFFER_LENGTH); + int bufferSize = list.size() / BUFFER_LENGTH; + for (int index = 0; index <= bufferSize; index++) { + temp.clear(); + if (index == bufferSize) { + for (int i = index * BUFFER_LENGTH; i < list.size(); i++) { + temp.add(list.get(i)); + } + } else { + for (int i = index * BUFFER_LENGTH; i < index * BUFFER_LENGTH + BUFFER_LENGTH; + i++) { + temp.add(list.get(i)); + } + } + if (!temp.isEmpty()) { + try { + cr.applyBatch(ContactsContract.AUTHORITY, temp); + if (mProgressDialog != null) { + mProgressDialog.incrementProgressBy(temp.size() / 4); + } else if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } + } catch (Exception e) { + Log.e(MemberListActivity.class.getSimpleName(), "apply batch by buffer error:" + e); + } + } + } + } + } } |