Home | History | Annotate | Download | only in calendar
      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 com.android.calendar.AgendaAdapter.ViewHolder;
     20 import com.android.calendar.AgendaWindowAdapter.EventInfo;
     21 
     22 import android.content.ContentUris;
     23 import android.content.Intent;
     24 import android.graphics.Rect;
     25 import android.net.Uri;
     26 import android.provider.Calendar;
     27 import android.provider.Calendar.Events;
     28 import android.text.format.Time;
     29 import android.util.Log;
     30 import android.view.View;
     31 import android.view.accessibility.AccessibilityEvent;
     32 import android.widget.AdapterView;
     33 import android.widget.AdapterView.OnItemClickListener;
     34 import android.widget.ListView;
     35 import android.widget.TextView;
     36 
     37 public class AgendaListView extends ListView implements OnItemClickListener {
     38 
     39     private static final String TAG = "AgendaListView";
     40     private static final boolean DEBUG = false;
     41 
     42     private AgendaWindowAdapter mWindowAdapter;
     43 
     44     private AgendaActivity mAgendaActivity;
     45     private DeleteEventHelper mDeleteEventHelper;
     46 
     47     /**
     48      * Reusable view to fetch the day title for accessibility support with no
     49      * code duplication reducing fragility.
     50      */
     51     private View mLazyTempView;
     52 
     53     // Placeholder if we need some code for updating the tz later.
     54     private Runnable mUpdateTZ = null;
     55 
     56     public AgendaListView(AgendaActivity agendaActivity) {
     57         super(agendaActivity, null);
     58         mAgendaActivity = agendaActivity;
     59 
     60         setOnItemClickListener(this);
     61         setChoiceMode(ListView.CHOICE_MODE_SINGLE);
     62         setVerticalScrollBarEnabled(false);
     63         mWindowAdapter = new AgendaWindowAdapter(agendaActivity, this);
     64         setAdapter(mWindowAdapter);
     65         mDeleteEventHelper =
     66             new DeleteEventHelper(agendaActivity, false /* don't exit when done */);
     67     }
     68 
     69     @Override protected void onDetachedFromWindow() {
     70         super.onDetachedFromWindow();
     71         mWindowAdapter.close();
     72     }
     73 
     74     @Override
     75     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
     76         int titlePosition = 0 ;
     77         AgendaByDayAdapter.RowInfo rowInfo = null;
     78         // find the index of the item with day title
     79         for (titlePosition = getSelectedItemPosition() - 1; titlePosition >= 0; titlePosition--) {
     80             Object previousItem = mWindowAdapter.getItem(titlePosition);
     81             if (previousItem instanceof AgendaByDayAdapter.RowInfo) {
     82                 break;
     83             }
     84         }
     85         // append the day title
     86         mLazyTempView = mWindowAdapter.getView(titlePosition, mLazyTempView, null);
     87         if (mLazyTempView != null && mLazyTempView instanceof TextView) {
     88             TextView weekDayTitleView = (TextView) mLazyTempView;
     89             CharSequence weekDayTitleViewText = weekDayTitleView.getText();
     90             event.getText().add(weekDayTitleViewText);
     91         }
     92         return super.dispatchPopulateAccessibilityEvent(event);
     93     }
     94 
     95     // Implementation of the interface OnItemClickListener
     96     public void onItemClick(AdapterView<?> a, View v, int position, long id) {
     97         if (id != -1) {
     98             // Switch to the EventInfo view
     99             EventInfo event = mWindowAdapter.getEventByPosition(position);
    100             if (event != null) {
    101                 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id);
    102                 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    103                 intent.putExtra(Calendar.EVENT_BEGIN_TIME, event.begin);
    104                 intent.putExtra(Calendar.EVENT_END_TIME, event.end);
    105                 mAgendaActivity.startActivity(intent);
    106             }
    107         }
    108     }
    109 
    110     public void goTo(Time time, boolean forced) {
    111         mWindowAdapter.refresh(time, forced);
    112     }
    113 
    114     public void refresh(boolean forced) {
    115         Time time = new Time(Utils.getTimeZone(mContext, mUpdateTZ));
    116         long goToTime = getFirstVisibleTime();
    117         if (goToTime <= 0) {
    118             goToTime = System.currentTimeMillis();
    119         }
    120         time.set(goToTime);
    121         mWindowAdapter.refresh(time, forced);
    122     }
    123 
    124     public void deleteSelectedEvent() {
    125         int position = getSelectedItemPosition();
    126         EventInfo event = mWindowAdapter.getEventByPosition(position);
    127         if (event != null) {
    128             mDeleteEventHelper.delete(event.begin, event.end, event.id, -1);
    129         }
    130     }
    131 
    132     @Override
    133     public int getFirstVisiblePosition() {
    134         // TODO File bug!
    135         // getFirstVisiblePosition doesn't always return the first visible
    136         // item. Sometimes, it is above the visible one.
    137         // instead. I loop through the viewgroup children and find the first
    138         // visible one. BTW, getFirstVisiblePosition() == getChildAt(0). I
    139         // am not looping through the entire list.
    140        View v = getFirstVisibleView();
    141        if (v != null) {
    142            if (DEBUG) {
    143                Log.v(TAG, "getFirstVisiblePosition: " + AgendaWindowAdapter.getViewTitle(v));
    144            }
    145            return getPositionForView(v);
    146        }
    147        return -1;
    148     }
    149 
    150     public View getFirstVisibleView() {
    151         Rect r = new Rect();
    152         int childCount = getChildCount();
    153         for (int i = 0; i < childCount; ++i) {
    154             View listItem = getChildAt(i);
    155             listItem.getLocalVisibleRect(r);
    156             if (r.top >= 0) { // if visible
    157                 return listItem;
    158             }
    159         }
    160         return null;
    161     }
    162 
    163     public long getSelectedTime() {
    164         int position = getSelectedItemPosition();
    165         if (position >= 0) {
    166             EventInfo event = mWindowAdapter.getEventByPosition(position);
    167             if (event != null) {
    168                 return event.begin;
    169             }
    170         }
    171         return getFirstVisibleTime();
    172     }
    173 
    174     public long getFirstVisibleTime() {
    175         int position = getFirstVisiblePosition();
    176         if (DEBUG) {
    177             Log.v(TAG, "getFirstVisiblePosition = " + position);
    178         }
    179 
    180         EventInfo event = mWindowAdapter.getEventByPosition(position);
    181         if (event != null) {
    182             return event.begin;
    183         }
    184         return 0;
    185     }
    186 
    187     // Move the currently selected or visible focus down by offset amount.
    188     // offset could be negative.
    189     public void shiftSelection(int offset) {
    190         shiftPosition(offset);
    191         int position = getSelectedItemPosition();
    192         if (position != INVALID_POSITION) {
    193             setSelectionFromTop(position + offset, 0);
    194         }
    195     }
    196 
    197     private void shiftPosition(int offset) {
    198         if (DEBUG) {
    199             Log.v(TAG, "Shifting position "+ offset);
    200         }
    201 
    202         View firstVisibleItem = getFirstVisibleView();
    203 
    204         if (firstVisibleItem != null) {
    205             Rect r = new Rect();
    206             firstVisibleItem.getLocalVisibleRect(r);
    207             // if r.top is < 0, getChildAt(0) and getFirstVisiblePosition() is
    208             // returning an item above the first visible item.
    209             int position = getPositionForView(firstVisibleItem);
    210             setSelectionFromTop(position + offset, r.top > 0 ? -r.top : r.top);
    211             if (DEBUG) {
    212                 if (firstVisibleItem.getTag() instanceof AgendaAdapter.ViewHolder) {
    213                     ViewHolder viewHolder = (AgendaAdapter.ViewHolder)firstVisibleItem.getTag();
    214                     Log.v(TAG, "Shifting from " + position + " by " + offset + ". Title "
    215                             + viewHolder.title.getText());
    216                 } else if (firstVisibleItem.getTag() instanceof AgendaByDayAdapter.ViewHolder) {
    217                     AgendaByDayAdapter.ViewHolder viewHolder =
    218                         (AgendaByDayAdapter.ViewHolder)firstVisibleItem.getTag();
    219                     Log.v(TAG, "Shifting from " + position + " by " + offset + ". Date  "
    220                             + viewHolder.dateView.getText());
    221                 } else if (firstVisibleItem instanceof TextView) {
    222                     Log.v(TAG, "Shifting: Looking at header here. " + getSelectedItemPosition());
    223                 }
    224             }
    225         } else if (getSelectedItemPosition() >= 0) {
    226             if (DEBUG) {
    227                 Log.v(TAG, "Shifting selection from " + getSelectedItemPosition() + " by " + offset);
    228             }
    229             setSelection(getSelectedItemPosition() + offset);
    230         }
    231     }
    232 
    233     public void setHideDeclinedEvents(boolean hideDeclined) {
    234         mWindowAdapter.setHideDeclinedEvents(hideDeclined);
    235     }
    236 
    237     public void onResume() {
    238         mWindowAdapter.notifyDataSetChanged();
    239     }
    240     public void onPause() {
    241         mWindowAdapter.notifyDataSetInvalidated();
    242     }
    243 }
    244