diff options
author | Aravind Asam <aasam@codeaurora.org> | 2014-03-05 19:09:25 -0800 |
---|---|---|
committer | Matt Garnes <matt@cyngn.com> | 2014-11-11 17:46:50 -0800 |
commit | 43f257945f1924256590858725d938519adfb37b (patch) | |
tree | dcf58996cb425a554f0866a0fb428386a69e2e13 | |
parent | 67be113ebee4fc9f3b19a1f857bdda9c1358c1ec (diff) | |
download | android_packages_apps_Calendar-43f257945f1924256590858725d938519adfb37b.tar.gz android_packages_apps_Calendar-43f257945f1924256590858725d938519adfb37b.tar.bz2 android_packages_apps_Calendar-43f257945f1924256590858725d938519adfb37b.zip |
Calendar: Support for deleting events (rest of the features)
* Includes highlight for selected items.
* Spinner-style select all, deselect all.
* Improvements asset files updated.
* Add the TW strings for it.
* Show the delete events menu as the config.
Change-Id: I1781bd8748487bc51da8988f7ae74927c0e179c1
-rw-r--r-- | res/drawable-hdpi/dropdown_ic_arrow.png | bin | 0 -> 1204 bytes | |||
-rw-r--r-- | res/drawable-mdpi/dropdown_ic_arrow.png | bin | 0 -> 1121 bytes | |||
-rw-r--r-- | res/drawable-xhdpi/dropdown_ic_arrow.png | bin | 0 -> 1428 bytes | |||
-rw-r--r-- | res/layout/action_mode.xml | 3 | ||||
-rw-r--r-- | res/layout/event_list_item.xml | 3 | ||||
-rw-r--r-- | res/menu-sw600dp-land/all_in_one_title_bar.xml | 5 | ||||
-rw-r--r-- | res/menu-sw600dp/all_in_one_title_bar.xml | 5 | ||||
-rw-r--r-- | res/menu/delete_events_title_bar.xml | 7 | ||||
-rw-r--r-- | res/menu/selection_popup.xml | 44 | ||||
-rw-r--r-- | res/values/cm_strings.xml | 3 | ||||
-rw-r--r-- | res/values/config.xml | 2 | ||||
-rw-r--r-- | src/com/android/calendar/AllInOneActivity.java | 53 | ||||
-rw-r--r-- | src/com/android/calendar/DeleteEventsActivity.java | 127 |
13 files changed, 224 insertions, 28 deletions
diff --git a/res/drawable-hdpi/dropdown_ic_arrow.png b/res/drawable-hdpi/dropdown_ic_arrow.png Binary files differnew file mode 100644 index 00000000..00b1a503 --- /dev/null +++ b/res/drawable-hdpi/dropdown_ic_arrow.png diff --git a/res/drawable-mdpi/dropdown_ic_arrow.png b/res/drawable-mdpi/dropdown_ic_arrow.png Binary files differnew file mode 100644 index 00000000..a99b8d41 --- /dev/null +++ b/res/drawable-mdpi/dropdown_ic_arrow.png diff --git a/res/drawable-xhdpi/dropdown_ic_arrow.png b/res/drawable-xhdpi/dropdown_ic_arrow.png Binary files differnew file mode 100644 index 00000000..076ad698 --- /dev/null +++ b/res/drawable-xhdpi/dropdown_ic_arrow.png diff --git a/res/layout/action_mode.xml b/res/layout/action_mode.xml index d7890182..f44ee5f4 100644 --- a/res/layout/action_mode.xml +++ b/res/layout/action_mode.xml @@ -30,7 +30,8 @@ <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_gravity="right" /> + android:layout_gravity="right" + android:src="@drawable/dropdown_ic_arrow" /> <Button android:id="@+id/selection_menu" diff --git a/res/layout/event_list_item.xml b/res/layout/event_list_item.xml index b9782341..2fc7f5e7 100644 --- a/res/layout/event_list_item.xml +++ b/res/layout/event_list_item.xml @@ -30,7 +30,8 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" > + android:layout_height="match_parent" + android:background="?android:attr/activatedBackgroundIndicator"> <CheckBox android:id="@+id/checkbox" diff --git a/res/menu-sw600dp-land/all_in_one_title_bar.xml b/res/menu-sw600dp-land/all_in_one_title_bar.xml index 97877eb2..57ad494c 100644 --- a/res/menu-sw600dp-land/all_in_one_title_bar.xml +++ b/res/menu-sw600dp-land/all_in_one_title_bar.xml @@ -42,6 +42,11 @@ android:actionViewClass="android.widget.SearchView" android:imeOptions="actionSearch" /> <item + android:id="@+id/action_delete_events" + android:alphabeticShortcut="d" + android:title="@string/events_delete" + android:showAsAction="never" /> + <item android:id="@+id/action_goto" android:title="@string/go_to" android:showAsAction="never"/> diff --git a/res/menu-sw600dp/all_in_one_title_bar.xml b/res/menu-sw600dp/all_in_one_title_bar.xml index 1a922a93..d463f137 100644 --- a/res/menu-sw600dp/all_in_one_title_bar.xml +++ b/res/menu-sw600dp/all_in_one_title_bar.xml @@ -42,6 +42,11 @@ android:actionViewClass="android.widget.SearchView" android:imeOptions="actionSearch" /> <item + android:id="@+id/action_delete_events" + android:alphabeticShortcut="d" + android:title="@string/events_delete" + android:showAsAction="never" /> + <item android:id="@+id/action_goto" android:title="@string/go_to" android:showAsAction="never"/> diff --git a/res/menu/delete_events_title_bar.xml b/res/menu/delete_events_title_bar.xml index 2ee9762a..87966453 100644 --- a/res/menu/delete_events_title_bar.xml +++ b/res/menu/delete_events_title_bar.xml @@ -32,16 +32,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <item android:id="@+id/action_delete" - android:icon="@drawable/ic_menu_trash_holo_light" android:showAsAction="always|withText" android:title="@string/action_delete" android:visible="true"> </item> - <item - android:id="@+id/action_select_all" - android:showAsAction="never" - android:title="@string/action_select_all"> - </item> </menu> - diff --git a/res/menu/selection_popup.xml b/res/menu/selection_popup.xml new file mode 100644 index 00000000..4a1cb09a --- /dev/null +++ b/res/menu/selection_popup.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (c) 2014, 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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <item + android:id="@+id/action_select_all" + android:title="@string/action_select_all" + android:visible="false"> + </item> + <item + android:id="@+id/action_select_none" + android:title="@string/action_select_none" + android:visible="false"> + </item> + +</menu> diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 0997df1f..ef2d53df 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -35,7 +35,8 @@ <!-- Delete Events related --> <string name="events_delete">Delete events</string> <string name="action_select_all">Select all</string> - <string name="action_delete">Delete</string> + <string name="action_select_none">Deselect all</string> + <string name="action_delete">Done</string> <string name="all_events">All events</string> <string name="no_events">No events available</string> <string name="selected">selected</string> diff --git a/res/values/config.xml b/res/values/config.xml index 73525931..d1031c2a 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -36,4 +36,6 @@ <bool name="multiple_pane_config">false</bool> <!-- A golbal var used to show goto menu --> <bool name="show_goto_menu">false</bool> + <!-- A golbal var used to show delete events menu --> + <bool name="show_delete_events_menu">false</bool> </resources> diff --git a/src/com/android/calendar/AllInOneActivity.java b/src/com/android/calendar/AllInOneActivity.java index 7567fa4c..66394591 100644 --- a/src/com/android/calendar/AllInOneActivity.java +++ b/src/com/android/calendar/AllInOneActivity.java @@ -32,13 +32,16 @@ import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; +import android.app.LoaderManager; import android.content.AsyncQueryHandler; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; +import android.content.CursorLoader; import android.content.DialogInterface; +import android.content.Loader; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; @@ -96,6 +99,7 @@ import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME; public class AllInOneActivity extends AbstractCalendarActivity implements EventHandler, OnSharedPreferenceChangeListener, SearchView.OnQueryTextListener, ActionBar.TabListener, + LoaderManager.LoaderCallbacks<Cursor>, ActionBar.OnNavigationListener, OnSuggestionListener { private static final String TAG = "AllInOneActivity"; private static final boolean DEBUG = false; @@ -160,7 +164,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH private SearchView mSearchView; private MenuItem mSearchMenu; private MenuItem mControlsMenu; - private MenuItem mGoToMenu; private Menu mOptionsMenu; private CalendarViewAdapter mActionBarMenuSpinnerAdapter; private QueryHandler mHandler; @@ -781,9 +784,16 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH mControlsMenu.setTitle(mHideControls ? mShowString : mHideString); } - mGoToMenu = menu.findItem(R.id.action_goto); + MenuItem deleteEventsMenu = menu.findItem(R.id.action_delete_events); + if (!getResources().getBoolean(R.bool.show_delete_events_menu)) { + deleteEventsMenu.setVisible(false); + } else { + getLoaderManager().initLoader(0, null, this); + } + + MenuItem goToMenu = menu.findItem(R.id.action_goto); if (!getResources().getBoolean(R.bool.show_goto_menu)) { - mGoToMenu.setVisible(false); + goToMenu.setVisible(false); } MenuItem menuItem = menu.findItem(R.id.action_today); @@ -795,6 +805,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH } else { menuItem.setIcon(R.drawable.ic_menu_today_no_date_holo_light); } + return true; } @@ -1380,6 +1391,42 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH return false; } + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + final String[] PROJECTION = new String[] { + CalendarContract.Events._ID, + CalendarContract.Events.TITLE, + CalendarContract.EventsEntity.DELETED + }; + final String where = CalendarContract.EventsEntity.DELETED + "=0 AND " + + Calendars.CALENDAR_ACCESS_LEVEL + ">=" + Calendars.CAL_ACCESS_CONTRIBUTOR; + return new CursorLoader(this, CalendarContract.EventsEntity.CONTENT_URI, + PROJECTION, where, null, null); + } + + @Override + public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) { + if (mOptionsMenu == null) { + Log.w(TAG, "mOptionsMenu is null"); + return; + } + + MenuItem delEventsMenu = mOptionsMenu.findItem(R.id.action_delete_events); + if (delEventsMenu != null) { + if (cursor.getCount() == 0) { + delEventsMenu.setEnabled(false); + } else { + delEventsMenu.setEnabled(true); + } + } + } + + @Override + public void onLoaderReset(Loader<Cursor> arg0) { + // Do nothing. + return; + } + public static class GoToDialogFragment extends DialogFragment { private static final String KEY_TIMEZONE = "timezone"; diff --git a/src/com/android/calendar/DeleteEventsActivity.java b/src/com/android/calendar/DeleteEventsActivity.java index 9d0631dd..f763675c 100644 --- a/src/com/android/calendar/DeleteEventsActivity.java +++ b/src/com/android/calendar/DeleteEventsActivity.java @@ -29,11 +29,6 @@ package com.android.calendar; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import android.app.ActionBar; import android.app.AlertDialog; import android.app.Dialog; @@ -58,14 +53,25 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.widget.Button; import android.widget.CheckBox; import android.widget.ListView; +import android.widget.PopupMenu; +import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.ResourceCursorAdapter; import android.widget.TextView; import android.widget.Toast; +import com.android.calendarcommon2.DateException; +import com.android.calendarcommon2.Duration; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class DeleteEventsActivity extends ListActivity - implements LoaderManager.LoaderCallbacks<Cursor> { + implements LoaderManager.LoaderCallbacks<Cursor>, OnMenuItemClickListener { private static final String TAG = "DeleteEvents"; private static final boolean DEBUG = false; @@ -97,6 +103,7 @@ public class DeleteEventsActivity extends ListActivity private EventListAdapter mAdapter; private AsyncQueryService mService; private TextView mHeaderTextView; + private Button mSelectionButton; private Map<Long, Long> mSelectedMap = new HashMap<Long, Long>(); private Map<Long, String> mCalendarsMap = new HashMap<Long, String>(); @@ -119,10 +126,14 @@ public class DeleteEventsActivity extends ListActivity super.onCreate(savedInstanceState); // actionbar setup - ActionBar actionBar = getActionBar(); + final ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowTitleEnabled(true); actionBar.setDisplayShowHomeEnabled(true); + actionBar.setCustomView(R.layout.action_mode); + actionBar.setDisplayShowCustomEnabled(true); + View view = actionBar.getCustomView(); + mSelectionButton = (Button) view.findViewById(R.id.selection_menu); updateTitle(); mListView = getListView(); @@ -171,6 +182,17 @@ public class DeleteEventsActivity extends ListActivity @Override protected void onResume() { super.onResume(); + + if (mSelectedMap.isEmpty() && mListView.getCheckedItemCount() > 0) { + long[] checkedItem = mListView.getCheckedItemIds(); + for (int i = 0; i < checkedItem.length; i++) { + if (DEBUG) Log.v(TAG, "onResume: " + checkedItem[i]); + mSelectedMap.put(checkedItem[i], checkedItem[i]); + } + mAdapter.notifyDataSetChanged(); + updateTitle(); + } + getContentResolver().registerContentObserver(CalendarContract.Calendars.CONTENT_URI, true, mObserver); } @@ -209,13 +231,7 @@ public class DeleteEventsActivity extends ListActivity return true; case R.id.action_select_all: if (DEBUG) Log.d(TAG, "Action: Select All"); - - mSelectedMap.clear(); - for (Long event : mEventList){ - mSelectedMap.put(event, event); - } - mAdapter.notifyDataSetChanged(); - updateTitle(); + selectAll(); return true; default: return super.onOptionsItemSelected(item); @@ -263,6 +279,8 @@ public class DeleteEventsActivity extends ListActivity ", RRULE: " + cursor.getString(cursor.getColumnIndex(Events.RRULE)) + ", RDATE: " + cursor.getString(cursor.getColumnIndex(Events.RDATE)) + ", DURATION: " + cursor.getString(cursor.getColumnIndex(Events.DURATION)) + + ", DTSTART: " + cursor.getString(cursor.getColumnIndex(Events.DTSTART)) + + ", DTEND: " + cursor.getString(cursor.getColumnIndex(Events.DTEND)) + ", LAST_DATE: " + cursor.getString(cursor.getColumnIndex(Events.LAST_DATE))); } if (DEBUG) Log.d(TAG, "mEventList: " + mEventList); @@ -293,6 +311,21 @@ public class DeleteEventsActivity extends ListActivity final TextView eventTime = (TextView) view.findViewById(R.id.event_time); long start = cursor.getLong(cursor.getColumnIndex(Events.DTSTART)); long end = cursor.getLong(cursor.getColumnIndex(Events.DTEND)); + + // if DTEND invalid, check for duration + if (end == 0) { + String durationStr = cursor.getString(cursor.getColumnIndex(Events.DURATION)); + Duration duration = new Duration(); + try { + duration.parse(durationStr); + end = start + duration.getMillis(); + } catch (DateException e) { + Log.w(TAG, e.getLocalizedMessage()); + } + } + if (DEBUG) Log.v(TAG, + "title: " + cursor.getString(cursor.getColumnIndex(Events.TITLE)) + + ", start: " + start + ", end: " + end); boolean allDay = cursor.getInt(cursor.getColumnIndex(Events.ALL_DAY)) != 0; eventTime.setText(getEventTimeString(start, end, allDay)); @@ -319,7 +352,7 @@ public class DeleteEventsActivity extends ListActivity } private void updateTitle() { - getActionBar().setTitle(" " + mSelectedMap.size() + " " + + mSelectionButton.setText(" " + mSelectedMap.size() + " " + getResources().getText(R.string.selected)); } @@ -389,4 +422,68 @@ public class DeleteEventsActivity extends ListActivity return builder.create(); } } + + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_select_all: + if (DEBUG) Log.d(TAG, "Select All"); + selectAll(); + return true; + case R.id.action_select_none: + if (DEBUG) Log.d(TAG, "Deselect all"); + selectNone(); + return true; + default: + return false; + } + } + + public void onSelectionButtonClicked(View v) { + if (DEBUG) Log.v(TAG, "onSelectionButtonClicked"); + PopupMenu popup = new PopupMenu(this, v); + MenuInflater inflater = popup.getMenuInflater(); + Menu menu = popup.getMenu(); + inflater.inflate(R.menu.selection_popup, menu); + MenuItem selectAll = menu.findItem(R.id.action_select_all); + MenuItem selectNone = menu.findItem(R.id.action_select_none); + + if (mEventList.size() == 0) { + selectAll.setVisible(true); + selectAll.setEnabled(false); + } + else if (mSelectedMap.size() == mEventList.size()) { + selectNone.setVisible(true); + } else { + selectAll.setVisible(true); + } + + popup.setOnMenuItemClickListener(this); + popup.show(); + } + + private void selectAll() { + mSelectedMap.clear(); + for (Long event : mEventList){ + mSelectedMap.put(event, event); + + } + + for (int i = 0; i < mListView.getCount(); i++) { + if (mSelectedMap.containsKey(mListView.getItemIdAtPosition(i))) { + mListView.setItemChecked(i, true); + } + } + mAdapter.notifyDataSetChanged(); + updateTitle(); + } + + private void selectNone() { + mSelectedMap.clear(); + for (int i = 0; i < mListView.getCount(); i++) { + mListView.setItemChecked(i, false); + } + mAdapter.notifyDataSetChanged(); + updateTitle(); + } } |