1 /* 2 * Copyright (C) 2013 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.app.Activity; 20 import android.app.Dialog; 21 import android.content.ContentUris; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.database.Cursor; 25 import android.net.Uri; 26 import android.os.Bundle; 27 import android.provider.CalendarContract.Calendars; 28 import android.provider.CalendarContract.Colors; 29 import android.util.SparseIntArray; 30 31 import com.android.colorpicker.ColorPickerDialog; 32 import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener; 33 import com.android.colorpicker.HsvColorComparator; 34 35 import java.util.ArrayList; 36 import java.util.Arrays; 37 38 public class CalendarColorPickerDialog extends ColorPickerDialog { 39 40 private static final int NUM_COLUMNS = 4; 41 42 private static final String KEY_CALENDAR_ID = "calendar_id"; 43 private static final String KEY_COLOR_KEYS = "color_keys"; 44 45 private static final int TOKEN_QUERY_CALENDARS = 1 << 1; 46 private static final int TOKEN_QUERY_COLORS = 1 << 2; 47 48 static final String[] CALENDARS_PROJECTION = new String[] { 49 Calendars.ACCOUNT_NAME, 50 Calendars.ACCOUNT_TYPE, 51 Calendars.CALENDAR_COLOR 52 }; 53 54 static final int CALENDARS_INDEX_ACCOUNT_NAME = 0; 55 static final int CALENDARS_INDEX_ACCOUNT_TYPE = 1; 56 static final int CALENDARS_INDEX_CALENDAR_COLOR = 2; 57 58 static final String[] COLORS_PROJECTION = new String[] { 59 Colors.COLOR, 60 Colors.COLOR_KEY 61 }; 62 63 static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE + 64 "=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_CALENDAR; 65 66 public static final int COLORS_INDEX_COLOR = 0; 67 public static final int COLORS_INDEX_COLOR_KEY = 1; 68 69 70 private QueryService mService; 71 private SparseIntArray mColorKeyMap = new SparseIntArray(); 72 private long mCalendarId; 73 74 private class QueryService extends AsyncQueryService { 75 QueryService(Context context)76 private QueryService(Context context) { 77 super(context); 78 } 79 80 @Override onQueryComplete(int token, Object cookie, Cursor cursor)81 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 82 // If the query didn't return a cursor for some reason return 83 if (cursor == null) { 84 return; 85 } 86 87 // If the Activity is finishing, then close the cursor. 88 // Otherwise, use the new cursor in the adapter. 89 final Activity activity = getActivity(); 90 if (activity == null || activity.isFinishing()) { 91 cursor.close(); 92 return; 93 } 94 95 switch (token) { 96 case TOKEN_QUERY_CALENDARS: 97 if (!cursor.moveToFirst()) { 98 cursor.close(); 99 dismiss(); 100 break; 101 } 102 mSelectedColor = Utils.getDisplayColorFromColor( 103 cursor.getInt(CALENDARS_INDEX_CALENDAR_COLOR)); 104 Uri uri = Colors.CONTENT_URI; 105 String[] args = new String[] { 106 cursor.getString(CALENDARS_INDEX_ACCOUNT_NAME), 107 cursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) }; 108 cursor.close(); 109 startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE, 110 args, null); 111 break; 112 case TOKEN_QUERY_COLORS: 113 if (!cursor.moveToFirst()) { 114 cursor.close(); 115 dismiss(); 116 break; 117 } 118 mColorKeyMap.clear(); 119 ArrayList<Integer> colors = new ArrayList<Integer>(); 120 do 121 { 122 int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY); 123 int rawColor = cursor.getInt(COLORS_INDEX_COLOR); 124 int displayColor = Utils.getDisplayColorFromColor(rawColor); 125 mColorKeyMap.put(displayColor, colorKey); 126 colors.add(displayColor); 127 } while (cursor.moveToNext()); 128 Integer[] colorsToSort = colors.toArray(new Integer[colors.size()]); 129 Arrays.sort(colorsToSort, new HsvColorComparator()); 130 mColors = new int[colorsToSort.length]; 131 for (int i = 0; i < mColors.length; i++) { 132 mColors[i] = colorsToSort[i]; 133 } 134 showPaletteView(); 135 cursor.close(); 136 break; 137 } 138 } 139 } 140 141 private class OnCalendarColorSelectedListener implements OnColorSelectedListener { 142 143 @Override onColorSelected(int color)144 public void onColorSelected(int color) { 145 if (color == mSelectedColor || mService == null) { 146 return; 147 } 148 149 ContentValues values = new ContentValues(); 150 values.put(Calendars.CALENDAR_COLOR_KEY, mColorKeyMap.get(color)); 151 mService.startUpdate(mService.getNextToken(), null, ContentUris.withAppendedId( 152 Calendars.CONTENT_URI, mCalendarId), values, null, null, Utils.UNDO_DELAY); 153 } 154 } 155 CalendarColorPickerDialog()156 public CalendarColorPickerDialog() { 157 // Empty constructor required for dialog fragments. 158 } 159 newInstance(long calendarId, boolean isTablet)160 public static CalendarColorPickerDialog newInstance(long calendarId, boolean isTablet) { 161 CalendarColorPickerDialog ret = new CalendarColorPickerDialog(); 162 ret.setArguments(R.string.calendar_color_picker_dialog_title, NUM_COLUMNS, 163 isTablet ? SIZE_LARGE : SIZE_SMALL); 164 ret.setCalendarId(calendarId); 165 return ret; 166 } 167 168 @Override onSaveInstanceState(Bundle outState)169 public void onSaveInstanceState(Bundle outState) { 170 super.onSaveInstanceState(outState); 171 outState.putLong(KEY_CALENDAR_ID, mCalendarId); 172 saveColorKeys(outState); 173 } 174 saveColorKeys(Bundle outState)175 private void saveColorKeys(Bundle outState) { 176 // No color keys to save, so just return 177 if (mColors == null) { 178 return; 179 } 180 int[] colorKeys = new int[mColors.length]; 181 for (int i = 0; i < mColors.length; i++) { 182 colorKeys[i] = mColorKeyMap.get(mColors[i]); 183 } 184 outState.putIntArray(KEY_COLOR_KEYS, colorKeys); 185 } 186 187 @Override onCreate(Bundle savedInstanceState)188 public void onCreate(Bundle savedInstanceState) { 189 super.onCreate(savedInstanceState); 190 if (savedInstanceState != null) { 191 mCalendarId = savedInstanceState.getLong(KEY_CALENDAR_ID); 192 retrieveColorKeys(savedInstanceState); 193 } 194 setOnColorSelectedListener(new OnCalendarColorSelectedListener()); 195 } 196 retrieveColorKeys(Bundle savedInstanceState)197 private void retrieveColorKeys(Bundle savedInstanceState) { 198 int[] colorKeys = savedInstanceState.getIntArray(KEY_COLOR_KEYS); 199 if (mColors != null && colorKeys != null) { 200 for (int i = 0; i < mColors.length; i++) { 201 mColorKeyMap.put(mColors[i], colorKeys[i]); 202 } 203 } 204 } 205 206 @Override setColors(int[] colors)207 public void setColors(int[] colors) { 208 throw new IllegalStateException("Must call setCalendarId() to update calendar colors"); 209 } 210 211 @Override setColors(int[] colors, int selectedColor)212 public void setColors(int[] colors, int selectedColor) { 213 throw new IllegalStateException("Must call setCalendarId() to update calendar colors"); 214 } 215 setCalendarId(long calendarId)216 public void setCalendarId(long calendarId) { 217 if (calendarId != mCalendarId) { 218 mCalendarId = calendarId; 219 startQuery(); 220 } 221 } 222 223 @Override onCreateDialog(Bundle savedInstanceState)224 public Dialog onCreateDialog(Bundle savedInstanceState) { 225 Dialog dialog = super.onCreateDialog(savedInstanceState); 226 mService = new QueryService(getActivity()); 227 if (mColors == null) { 228 startQuery(); 229 } 230 return dialog; 231 } 232 startQuery()233 private void startQuery() { 234 if (mService != null) { 235 showProgressBarView(); 236 mService.startQuery(TOKEN_QUERY_CALENDARS, null, 237 ContentUris.withAppendedId(Calendars.CONTENT_URI, mCalendarId), 238 CALENDARS_PROJECTION, null, null, null); 239 } 240 } 241 } 242