1 /*
2  * Copyright (C) 2010 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 package com.android.calendar.event;
17 
18 import com.android.calendar.CalendarEventModel.ReminderEntry;
19 import com.android.calendar.R;
20 
21 import android.app.Activity;
22 import android.content.Context;
23 import android.content.res.Resources;
24 import android.util.Log;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.widget.AdapterView.OnItemSelectedListener;
28 import android.widget.ArrayAdapter;
29 import android.widget.ImageButton;
30 import android.widget.LinearLayout;
31 import android.widget.Spinner;
32 
33 import java.util.ArrayList;
34 
35 public class EventViewUtils {
36     private static final String TAG = "EventViewUtils";
37 
EventViewUtils()38     private EventViewUtils() {
39     }
40 
41     // Constructs a label given an arbitrary number of minutes. For example,
42     // if the given minutes is 63, then this returns the string "63 minutes".
43     // As another example, if the given minutes is 120, then this returns
44     // "2 hours".
constructReminderLabel(Context context, int minutes, boolean abbrev)45     public static String constructReminderLabel(Context context, int minutes, boolean abbrev) {
46         Resources resources = context.getResources();
47         int value, resId;
48 
49         if (minutes % 60 != 0) {
50             value = minutes;
51             if (abbrev) {
52                 resId = R.plurals.Nmins;
53             } else {
54                 resId = R.plurals.Nminutes;
55             }
56         } else if (minutes % (24 * 60) != 0) {
57             value = minutes / 60;
58             resId = R.plurals.Nhours;
59         } else {
60             value = minutes / (24 * 60);
61             resId = R.plurals.Ndays;
62         }
63 
64         String format = resources.getQuantityString(resId, value);
65         return String.format(format, value);
66     }
67 
68     /**
69      * Finds the index of the given "minutes" in the "values" list.
70      *
71      * @param values the list of minutes corresponding to the spinner choices
72      * @param minutes the minutes to search for in the values list
73      * @return the index of "minutes" in the "values" list
74      */
findMinutesInReminderList(ArrayList<Integer> values, int minutes)75     public static int findMinutesInReminderList(ArrayList<Integer> values, int minutes) {
76         int index = values.indexOf(minutes);
77         if (index == -1) {
78             // This should never happen.
79             Log.e(TAG, "Cannot find minutes (" + minutes + ") in list");
80             return 0;
81         }
82         return index;
83     }
84 
85     /**
86      * Finds the index of the given method in the "methods" list.  If the method isn't present
87      * (perhaps because we don't think it's allowed for this calendar), we return zero (the
88      * first item in the list).
89      * <p>
90      * With the current definitions, this effectively converts DEFAULT and unsupported method
91      * types to ALERT.
92      *
93      * @param values the list of minutes corresponding to the spinner choices
94      * @param method the method to search for in the values list
95      * @return the index of the method in the "values" list
96      */
findMethodInReminderList(ArrayList<Integer> values, int method)97     public static int findMethodInReminderList(ArrayList<Integer> values, int method) {
98         int index = values.indexOf(method);
99         if (index == -1) {
100             // If not allowed, or undefined, just use the first entry in the list.
101             //Log.d(TAG, "Cannot find method (" + method + ") in allowed list");
102             index = 0;
103         }
104         return index;
105     }
106 
107     /**
108      * Extracts reminder minutes info from UI elements.
109      *
110      * @param reminderItems UI elements (layouts with spinners) that hold array indices.
111      * @param reminderMinuteValues Maps array index to time in minutes.
112      * @param reminderMethodValues Maps array index to alert method constant.
113      * @return Array with reminder data.
114      */
reminderItemsToReminders( ArrayList<LinearLayout> reminderItems, ArrayList<Integer> reminderMinuteValues, ArrayList<Integer> reminderMethodValues)115     public static ArrayList<ReminderEntry> reminderItemsToReminders(
116             ArrayList<LinearLayout> reminderItems, ArrayList<Integer> reminderMinuteValues,
117             ArrayList<Integer> reminderMethodValues) {
118         int len = reminderItems.size();
119         ArrayList<ReminderEntry> reminders = new ArrayList<ReminderEntry>(len);
120         for (int index = 0; index < len; index++) {
121             LinearLayout layout = reminderItems.get(index);
122             Spinner minuteSpinner = (Spinner) layout.findViewById(R.id.reminder_minutes_value);
123             Spinner methodSpinner = (Spinner) layout.findViewById(R.id.reminder_method_value);
124             int minutes = reminderMinuteValues.get(minuteSpinner.getSelectedItemPosition());
125             int method = reminderMethodValues.get(methodSpinner.getSelectedItemPosition());
126             reminders.add(ReminderEntry.valueOf(minutes, method));
127         }
128         return reminders;
129     }
130 
131     /**
132      * If "minutes" is not currently present in "values", we add an appropriate new entry
133      * to values and labels.
134      */
addMinutesToList(Context context, ArrayList<Integer> values, ArrayList<String> labels, int minutes)135     public static void addMinutesToList(Context context, ArrayList<Integer> values,
136             ArrayList<String> labels, int minutes) {
137         int index = values.indexOf(minutes);
138         if (index != -1) {
139             return;
140         }
141 
142         // The requested "minutes" does not exist in the list, so insert it
143         // into the list.
144 
145         String label = constructReminderLabel(context, minutes, false);
146         int len = values.size();
147         for (int i = 0; i < len; i++) {
148             if (minutes < values.get(i)) {
149                 values.add(i, minutes);
150                 labels.add(i, label);
151                 return;
152             }
153         }
154 
155         values.add(minutes);
156         labels.add(len, label);
157     }
158 
159     /**
160      * Remove entries from the method list that aren't allowed for this calendar.
161      *
162      * @param values List of known method values.
163      * @param labels List of known method labels.
164      * @param allowedMethods Has the form "0,1,3", indicating method constants from Reminders.
165      */
reduceMethodList(ArrayList<Integer> values, ArrayList<String> labels, String allowedMethods)166     public static void reduceMethodList(ArrayList<Integer> values, ArrayList<String> labels,
167             String allowedMethods)
168     {
169         // Parse "allowedMethods".
170         String[] allowedStrings = allowedMethods.split(",");
171         int[] allowedValues = new int[allowedStrings.length];
172 
173         for (int i = 0; i < allowedValues.length; i++) {
174             try {
175                 allowedValues[i] = Integer.parseInt(allowedStrings[i], 10);
176             } catch (NumberFormatException nfe) {
177                 Log.w(TAG, "Bad allowed-strings list: '" + allowedStrings[i] +
178                         "' in '" + allowedMethods + "'");
179                 return;
180             }
181         }
182 
183         // Walk through the method list, removing entries that aren't in the allowed list.
184         for (int i = values.size() - 1; i >= 0; i--) {
185             int val = values.get(i);
186             int j;
187 
188             for (j = allowedValues.length - 1; j >= 0; j--) {
189                 if (val == allowedValues[j]) {
190                     break;
191                 }
192             }
193             if (j < 0) {
194                 values.remove(i);
195                 labels.remove(i);
196             }
197         }
198     }
199 
200     /**
201      * Set the list of labels on a reminder spinner.
202      */
setReminderSpinnerLabels(Activity activity, Spinner spinner, ArrayList<String> labels)203     private static void setReminderSpinnerLabels(Activity activity, Spinner spinner,
204             ArrayList<String> labels) {
205         Resources res = activity.getResources();
206         spinner.setPrompt(res.getString(R.string.reminders_label));
207         int resource = android.R.layout.simple_spinner_item;
208         ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity, resource, labels);
209         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
210         spinner.setAdapter(adapter);
211     }
212 
213     /**
214      * Adds a reminder to the displayed list of reminders. The values/labels
215      * arrays must not change after calling here, or the spinners we created
216      * might index into the wrong entry. Returns true if successfully added
217      * reminder, false if no reminders can be added.
218      *
219      * onItemSelected allows a listener to be set for any changes to the
220      * spinners in the reminder. If a listener is set it will store the
221      * initial position of the spinner into the spinner's tag for comparison
222      * with any new position setting.
223      */
addReminder(Activity activity, View view, View.OnClickListener listener, ArrayList<LinearLayout> items, ArrayList<Integer> minuteValues, ArrayList<String> minuteLabels, ArrayList<Integer> methodValues, ArrayList<String> methodLabels, ReminderEntry newReminder, int maxReminders, OnItemSelectedListener onItemSelected)224     public static boolean addReminder(Activity activity, View view, View.OnClickListener listener,
225             ArrayList<LinearLayout> items, ArrayList<Integer> minuteValues,
226             ArrayList<String> minuteLabels, ArrayList<Integer> methodValues,
227             ArrayList<String> methodLabels, ReminderEntry newReminder, int maxReminders,
228             OnItemSelectedListener onItemSelected) {
229 
230         if (items.size() >= maxReminders) {
231             return false;
232         }
233 
234         LayoutInflater inflater = activity.getLayoutInflater();
235         LinearLayout parent = (LinearLayout) view.findViewById(R.id.reminder_items_container);
236         LinearLayout reminderItem = (LinearLayout) inflater.inflate(R.layout.edit_reminder_item,
237                 null);
238         parent.addView(reminderItem);
239 
240         ImageButton reminderRemoveButton;
241         reminderRemoveButton = (ImageButton) reminderItem.findViewById(R.id.reminder_remove);
242         reminderRemoveButton.setOnClickListener(listener);
243 
244         /*
245          * The spinner has the default set of labels from the string resource file, but we
246          * want to drop in our custom set of labels because it may have additional entries.
247          */
248         Spinner spinner = (Spinner) reminderItem.findViewById(R.id.reminder_minutes_value);
249         setReminderSpinnerLabels(activity, spinner, minuteLabels);
250 
251         int index = findMinutesInReminderList(minuteValues, newReminder.getMinutes());
252         spinner.setSelection(index);
253 
254         if (onItemSelected != null) {
255             spinner.setTag(index);
256             spinner.setOnItemSelectedListener(onItemSelected);
257         }
258 
259         /*
260          * Configure the alert-method spinner.  Methods not supported by the current Calendar
261          * will not be shown.
262          */
263         spinner = (Spinner) reminderItem.findViewById(R.id.reminder_method_value);
264         setReminderSpinnerLabels(activity, spinner, methodLabels);
265 
266         index = findMethodInReminderList(methodValues, newReminder.getMethod());
267         spinner.setSelection(index);
268 
269         if (onItemSelected != null) {
270             spinner.setTag(index);
271             spinner.setOnItemSelectedListener(onItemSelected);
272         }
273 
274         items.add(reminderItem);
275 
276         return true;
277     }
278 
279     /**
280      * Enables/disables the 'add reminder' button depending on the current number of
281      * reminders.
282      */
updateAddReminderButton(View view, ArrayList<LinearLayout> reminders, int maxReminders)283     public static void updateAddReminderButton(View view, ArrayList<LinearLayout> reminders,
284             int maxReminders) {
285         View reminderAddButton = view.findViewById(R.id.reminder_add);
286         if (reminderAddButton != null) {
287             if (reminders.size() >= maxReminders) {
288                 reminderAddButton.setEnabled(false);
289                 reminderAddButton.setVisibility(View.GONE);
290             } else {
291                 reminderAddButton.setEnabled(true);
292                 reminderAddButton.setVisibility(View.VISIBLE);
293             }
294         }
295     }
296 }
297