1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.calendar; 18 19 import android.content.ContentUris; 20 import android.content.Intent; 21 import android.graphics.Rect; 22 import android.net.Uri; 23 import android.provider.Calendar; 24 import android.provider.Calendar.Events; 25 import android.text.format.Time; 26 import android.util.Log; 27 import android.view.View; 28 import android.widget.AdapterView; 29 import android.widget.ListView; 30 import android.widget.TextView; 31 import android.widget.AdapterView.OnItemClickListener; 32 33 import com.android.calendar.AgendaAdapter.ViewHolder; 34 import com.android.calendar.AgendaWindowAdapter.EventInfo; 35 36 public class AgendaListView extends ListView implements OnItemClickListener { 37 38 private static final String TAG = "AgendaListView"; 39 private static final boolean DEBUG = false; 40 41 private AgendaWindowAdapter mWindowAdapter; 42 43 private AgendaActivity mAgendaActivity; 44 private DeleteEventHelper mDeleteEventHelper; 45 AgendaListView(AgendaActivity agendaActivity)46 public AgendaListView(AgendaActivity agendaActivity) { 47 super(agendaActivity, null); 48 mAgendaActivity = agendaActivity; 49 mContext = agendaActivity; 50 51 setOnItemClickListener(this); 52 setChoiceMode(ListView.CHOICE_MODE_SINGLE); 53 setVerticalScrollBarEnabled(false); 54 mWindowAdapter = new AgendaWindowAdapter(agendaActivity, this); 55 setAdapter(mWindowAdapter); 56 mDeleteEventHelper = 57 new DeleteEventHelper(agendaActivity, false /* don't exit when done */); 58 } 59 onDetachedFromWindow()60 @Override protected void onDetachedFromWindow() { 61 super.onDetachedFromWindow(); 62 mWindowAdapter.close(); 63 } 64 65 // Implementation of the interface OnItemClickListener onItemClick(AdapterView<?> a, View v, int position, long id)66 public void onItemClick(AdapterView<?> a, View v, int position, long id) { 67 if (id != -1) { 68 // Switch to the EventInfo view 69 EventInfo event = mWindowAdapter.getEventByPosition(position); 70 if (event != null) { 71 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id); 72 Intent intent = new Intent(Intent.ACTION_VIEW, uri); 73 intent.putExtra(Calendar.EVENT_BEGIN_TIME, event.begin); 74 intent.putExtra(Calendar.EVENT_END_TIME, event.end); 75 mAgendaActivity.startActivity(intent); 76 } 77 } 78 } 79 goTo(Time time, boolean forced)80 public void goTo(Time time, boolean forced) { 81 mWindowAdapter.refresh(time, forced); 82 } 83 refresh(boolean forced)84 public void refresh(boolean forced) { 85 Time time = new Time(); 86 long goToTime = getFirstVisibleTime(); 87 if (goToTime <= 0) { 88 goToTime = System.currentTimeMillis(); 89 } 90 time.set(goToTime); 91 mWindowAdapter.refresh(time, forced); 92 } 93 deleteSelectedEvent()94 public void deleteSelectedEvent() { 95 int position = getSelectedItemPosition(); 96 EventInfo event = mWindowAdapter.getEventByPosition(position); 97 if (event != null) { 98 mDeleteEventHelper.delete(event.begin, event.end, event.id, -1); 99 } 100 } 101 102 @Override getFirstVisiblePosition()103 public int getFirstVisiblePosition() { 104 // TODO File bug! 105 // getFirstVisiblePosition doesn't always return the first visible 106 // item. Sometimes, it is above the visible one. 107 // instead. I loop through the viewgroup children and find the first 108 // visible one. BTW, getFirstVisiblePosition() == getChildAt(0). I 109 // am not looping through the entire list. 110 View v = getFirstVisibleView(); 111 if (v != null) { 112 if (DEBUG) { 113 Log.v(TAG, "getFirstVisiblePosition: " + AgendaWindowAdapter.getViewTitle(v)); 114 } 115 return getPositionForView(v); 116 } 117 return -1; 118 } 119 getFirstVisibleView()120 public View getFirstVisibleView() { 121 Rect r = new Rect(); 122 int childCount = getChildCount(); 123 for (int i = 0; i < childCount; ++i) { 124 View listItem = getChildAt(i); 125 listItem.getLocalVisibleRect(r); 126 if (r.top >= 0) { // if visible 127 return listItem; 128 } 129 } 130 return null; 131 } 132 getSelectedTime()133 public long getSelectedTime() { 134 int position = getSelectedItemPosition(); 135 if (position >= 0) { 136 EventInfo event = mWindowAdapter.getEventByPosition(position); 137 if (event != null) { 138 return event.begin; 139 } 140 } 141 return getFirstVisibleTime(); 142 } 143 getFirstVisibleTime()144 public long getFirstVisibleTime() { 145 int position = getFirstVisiblePosition(); 146 if (DEBUG) { 147 Log.v(TAG, "getFirstVisiblePosition = " + position); 148 } 149 150 EventInfo event = mWindowAdapter.getEventByPosition(position); 151 if (event != null) { 152 return event.begin; 153 } 154 return 0; 155 } 156 157 // Move the currently selected or visible focus down by offset amount. 158 // offset could be negative. shiftSelection(int offset)159 public void shiftSelection(int offset) { 160 shiftPosition(offset); 161 int position = getSelectedItemPosition(); 162 if (position != INVALID_POSITION) { 163 setSelectionFromTop(position + offset, 0); 164 } 165 } 166 shiftPosition(int offset)167 private void shiftPosition(int offset) { 168 if (DEBUG) { 169 Log.v(TAG, "Shifting position "+ offset); 170 } 171 172 View firstVisibleItem = getFirstVisibleView(); 173 174 if (firstVisibleItem != null) { 175 Rect r = new Rect(); 176 firstVisibleItem.getLocalVisibleRect(r); 177 // if r.top is < 0, getChildAt(0) and getFirstVisiblePosition() is 178 // returning an item above the first visible item. 179 int position = getPositionForView(firstVisibleItem); 180 setSelectionFromTop(position + offset, r.top > 0 ? -r.top : r.top); 181 if (DEBUG) { 182 if (firstVisibleItem.getTag() instanceof AgendaAdapter.ViewHolder) { 183 ViewHolder viewHolder = (AgendaAdapter.ViewHolder)firstVisibleItem.getTag(); 184 Log.v(TAG, "Shifting from " + position + " by " + offset + ". Title " 185 + viewHolder.title.getText()); 186 } else if (firstVisibleItem.getTag() instanceof AgendaByDayAdapter.ViewHolder) { 187 AgendaByDayAdapter.ViewHolder viewHolder = 188 (AgendaByDayAdapter.ViewHolder)firstVisibleItem.getTag(); 189 Log.v(TAG, "Shifting from " + position + " by " + offset + ". Date " 190 + viewHolder.dateView.getText()); 191 } else if (firstVisibleItem instanceof TextView) { 192 Log.v(TAG, "Shifting: Looking at header here. " + getSelectedItemPosition()); 193 } 194 } 195 } else if (getSelectedItemPosition() >= 0) { 196 if (DEBUG) { 197 Log.v(TAG, "Shifting selection from " + getSelectedItemPosition() + " by " + offset); 198 } 199 setSelection(getSelectedItemPosition() + offset); 200 } 201 } 202 setHideDeclinedEvents(boolean hideDeclined)203 public void setHideDeclinedEvents(boolean hideDeclined) { 204 mWindowAdapter.setHideDeclinedEvents(hideDeclined); 205 } 206 onResume()207 public void onResume() { 208 mWindowAdapter.notifyDataSetChanged(); 209 } onPause()210 public void onPause() { 211 mWindowAdapter.notifyDataSetInvalidated(); 212 } 213 } 214