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