mirror of
https://github.com/Etar-Group/Etar-Calendar.git
synced 2024-10-26 03:56:57 +03:00
Change package name.
This commit is contained in:
parent
e3ee56b0d5
commit
82c14f0be5
@ -18,10 +18,10 @@
|
||||
*/
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.sufficientlysecure.standalonecalendar"
|
||||
package="ws.xsoh.etar"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="3"
|
||||
android:versionName="standalone-1.2" >
|
||||
android:versionCode="4"
|
||||
android:versionName="1.0">
|
||||
<!-- android:sharedUserLabel="@string/app_label"> -->
|
||||
|
||||
<!--
|
||||
|
@ -15,7 +15,7 @@ def findReplace(directory, find, replace, filePattern):
|
||||
findReplace("res", r"(<string name=\"custom\" product=\"tablet\".*>).*(</string>)", r"", "strings.xml")
|
||||
|
||||
# change import of generated R file to fix packagename
|
||||
findReplace("src", r"import com.android.calendar.R;", r"import org.sufficientlysecure.standalonecalendar.R;", "*.java")
|
||||
findReplace("src", r"import com.android.calendar.R;", r"import ws.xsoh.etar.R;", "*.java")
|
||||
|
||||
# add R import to com.android.calendar
|
||||
findReplace("src", r"package com.android.calendar;", r"package com.android.calendar;\n\nimport org.sufficientlysecure.standalonecalendar.R;", "*.java")
|
||||
findReplace("src", r"package com.android.calendar;", r"package com.android.calendar;\n\nimport ws.xsoh.etar.R;", "*.java")
|
||||
|
@ -16,15 +16,13 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceFragment;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AboutPreferences extends PreferenceFragment {
|
||||
private static final String BUILD_VERSION = "build_version";
|
||||
|
@ -76,13 +76,13 @@ import com.android.calendar.agenda.AgendaFragment;
|
||||
import com.android.calendar.month.MonthByWeekFragment;
|
||||
import com.android.calendar.selectcalendars.SelectVisibleCalendarsFragment;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
@ -192,15 +192,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
|
||||
private MenuItem mControlsMenu;
|
||||
private Menu mOptionsMenu;
|
||||
private QueryHandler mHandler;
|
||||
// runs every midnight/time changes and refreshes the today icon
|
||||
private final Runnable mTimeChangesUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTimeZone = Utils.getTimeZone(AllInOneActivity.this, mHomeTimeUpdater);
|
||||
AllInOneActivity.this.invalidateOptionsMenu();
|
||||
Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
|
||||
}
|
||||
};
|
||||
private final Runnable mHomeTimeUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -210,6 +201,15 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
|
||||
Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
|
||||
}
|
||||
};
|
||||
// runs every midnight/time changes and refreshes the today icon
|
||||
private final Runnable mTimeChangesUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTimeZone = Utils.getTimeZone(AllInOneActivity.this, mHomeTimeUpdater);
|
||||
AllInOneActivity.this.invalidateOptionsMenu();
|
||||
Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
|
||||
}
|
||||
};
|
||||
private boolean mCheckForAccounts = true;
|
||||
private String mHideString;
|
||||
private String mShowString;
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.calendar.AsyncQueryServiceHelper.OperationInfo;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentResolver;
|
||||
@ -31,6 +27,8 @@ import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.calendar.AsyncQueryServiceHelper.OperationInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ -46,71 +44,14 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* application which serializes all the calls.
|
||||
*/
|
||||
public class AsyncQueryService extends Handler {
|
||||
private static final String TAG = "AsyncQuery";
|
||||
static final boolean localLOGV = false;
|
||||
|
||||
private static final String TAG = "AsyncQuery";
|
||||
// Used for generating unique tokens for calls to this service
|
||||
private static AtomicInteger mUniqueToken = new AtomicInteger(0);
|
||||
|
||||
private Context mContext;
|
||||
private Handler mHandler = this; // can be overridden for testing
|
||||
|
||||
/**
|
||||
* Data class which holds into info of the queued operation
|
||||
*/
|
||||
public static class Operation {
|
||||
static final int EVENT_ARG_QUERY = 1;
|
||||
static final int EVENT_ARG_INSERT = 2;
|
||||
static final int EVENT_ARG_UPDATE = 3;
|
||||
static final int EVENT_ARG_DELETE = 4;
|
||||
static final int EVENT_ARG_BATCH = 5;
|
||||
|
||||
/**
|
||||
* unique identify for cancellation purpose
|
||||
*/
|
||||
public int token;
|
||||
|
||||
/**
|
||||
* One of the EVENT_ARG_ constants in the class describing the operation
|
||||
*/
|
||||
public int op;
|
||||
|
||||
/**
|
||||
* {@link SystemClock.elapsedRealtime()} based
|
||||
*/
|
||||
public long scheduledExecutionTime;
|
||||
|
||||
protected static char opToChar(int op) {
|
||||
switch (op) {
|
||||
case Operation.EVENT_ARG_QUERY:
|
||||
return 'Q';
|
||||
case Operation.EVENT_ARG_INSERT:
|
||||
return 'I';
|
||||
case Operation.EVENT_ARG_UPDATE:
|
||||
return 'U';
|
||||
case Operation.EVENT_ARG_DELETE:
|
||||
return 'D';
|
||||
case Operation.EVENT_ARG_BATCH:
|
||||
return 'B';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Operation [op=");
|
||||
builder.append(op);
|
||||
builder.append(", token=");
|
||||
builder.append(token);
|
||||
builder.append(", scheduledExecutionTime=");
|
||||
builder.append(scheduledExecutionTime);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncQueryService(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
@ -436,4 +377,60 @@ public class AsyncQueryService extends Handler {
|
||||
protected void setTestHandler(Handler handler) {
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class which holds into info of the queued operation
|
||||
*/
|
||||
public static class Operation {
|
||||
static final int EVENT_ARG_QUERY = 1;
|
||||
static final int EVENT_ARG_INSERT = 2;
|
||||
static final int EVENT_ARG_UPDATE = 3;
|
||||
static final int EVENT_ARG_DELETE = 4;
|
||||
static final int EVENT_ARG_BATCH = 5;
|
||||
|
||||
/**
|
||||
* unique identify for cancellation purpose
|
||||
*/
|
||||
public int token;
|
||||
|
||||
/**
|
||||
* One of the EVENT_ARG_ constants in the class describing the operation
|
||||
*/
|
||||
public int op;
|
||||
|
||||
/**
|
||||
* {@link SystemClock.elapsedRealtime()} based
|
||||
*/
|
||||
public long scheduledExecutionTime;
|
||||
|
||||
protected static char opToChar(int op) {
|
||||
switch (op) {
|
||||
case Operation.EVENT_ARG_QUERY:
|
||||
return 'Q';
|
||||
case Operation.EVENT_ARG_INSERT:
|
||||
return 'I';
|
||||
case Operation.EVENT_ARG_UPDATE:
|
||||
return 'U';
|
||||
case Operation.EVENT_ARG_DELETE:
|
||||
return 'D';
|
||||
case Operation.EVENT_ARG_BATCH:
|
||||
return 'B';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Operation [op=");
|
||||
builder.append(op);
|
||||
builder.append(", token=");
|
||||
builder.append(token);
|
||||
builder.append(", scheduledExecutionTime=");
|
||||
builder.append(scheduledExecutionTime);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.calendar.AsyncQueryService.Operation;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
@ -35,6 +31,8 @@ import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.calendar.AsyncQueryService.Operation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
@ -50,106 +48,12 @@ public class AsyncQueryServiceHelper extends IntentService {
|
||||
|
||||
protected Class<AsyncQueryService> mService = AsyncQueryService.class;
|
||||
|
||||
protected static class OperationInfo implements Delayed{
|
||||
public int token; // Used for cancel
|
||||
public int op;
|
||||
public ContentResolver resolver;
|
||||
public Uri uri;
|
||||
public String authority;
|
||||
public Handler handler;
|
||||
public String[] projection;
|
||||
public String selection;
|
||||
public String[] selectionArgs;
|
||||
public String orderBy;
|
||||
public Object result;
|
||||
public Object cookie;
|
||||
public ContentValues values;
|
||||
public ArrayList<ContentProviderOperation> cpo;
|
||||
public AsyncQueryServiceHelper(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* delayMillis is relative time e.g. 10,000 milliseconds
|
||||
*/
|
||||
public long delayMillis;
|
||||
|
||||
/**
|
||||
* scheduleTimeMillis is the time scheduled for this to be processed.
|
||||
* e.g. SystemClock.elapsedRealtime() + 10,000 milliseconds Based on
|
||||
* {@link android.os.SystemClock#elapsedRealtime }
|
||||
*/
|
||||
private long mScheduledTimeMillis = 0;
|
||||
|
||||
// @VisibleForTesting
|
||||
void calculateScheduledTime() {
|
||||
mScheduledTimeMillis = SystemClock.elapsedRealtime() + delayMillis;
|
||||
}
|
||||
|
||||
// @Override // Uncomment with Java6
|
||||
public long getDelay(TimeUnit unit) {
|
||||
return unit.convert(mScheduledTimeMillis - SystemClock.elapsedRealtime(),
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
// @Override // Uncomment with Java6
|
||||
public int compareTo(Delayed another) {
|
||||
OperationInfo anotherArgs = (OperationInfo) another;
|
||||
if (this.mScheduledTimeMillis == anotherArgs.mScheduledTimeMillis) {
|
||||
return 0;
|
||||
} else if (this.mScheduledTimeMillis < anotherArgs.mScheduledTimeMillis) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("OperationInfo [\n\t token= ");
|
||||
builder.append(token);
|
||||
builder.append(",\n\t op= ");
|
||||
builder.append(Operation.opToChar(op));
|
||||
builder.append(",\n\t uri= ");
|
||||
builder.append(uri);
|
||||
builder.append(",\n\t authority= ");
|
||||
builder.append(authority);
|
||||
builder.append(",\n\t delayMillis= ");
|
||||
builder.append(delayMillis);
|
||||
builder.append(",\n\t mScheduledTimeMillis= ");
|
||||
builder.append(mScheduledTimeMillis);
|
||||
builder.append(",\n\t resolver= ");
|
||||
builder.append(resolver);
|
||||
builder.append(",\n\t handler= ");
|
||||
builder.append(handler);
|
||||
builder.append(",\n\t projection= ");
|
||||
builder.append(Arrays.toString(projection));
|
||||
builder.append(",\n\t selection= ");
|
||||
builder.append(selection);
|
||||
builder.append(",\n\t selectionArgs= ");
|
||||
builder.append(Arrays.toString(selectionArgs));
|
||||
builder.append(",\n\t orderBy= ");
|
||||
builder.append(orderBy);
|
||||
builder.append(",\n\t result= ");
|
||||
builder.append(result);
|
||||
builder.append(",\n\t cookie= ");
|
||||
builder.append(cookie);
|
||||
builder.append(",\n\t values= ");
|
||||
builder.append(values);
|
||||
builder.append(",\n\t cpo= ");
|
||||
builder.append(cpo);
|
||||
builder.append("\n]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares an user-visible operation to this private OperationInfo
|
||||
* object
|
||||
*
|
||||
* @param o operation to be compared
|
||||
* @return true if logically equivalent
|
||||
*/
|
||||
public boolean equivalent(Operation o) {
|
||||
return o.token == this.token && o.op == this.op;
|
||||
}
|
||||
public AsyncQueryServiceHelper() {
|
||||
super("AsyncQueryServiceHelper");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,14 +137,6 @@ public class AsyncQueryServiceHelper extends IntentService {
|
||||
return canceled;
|
||||
}
|
||||
|
||||
public AsyncQueryServiceHelper(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public AsyncQueryServiceHelper() {
|
||||
super("AsyncQueryServiceHelper");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
OperationInfo args;
|
||||
@ -377,4 +273,106 @@ public class AsyncQueryServiceHelper extends IntentService {
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
protected static class OperationInfo implements Delayed {
|
||||
public int token; // Used for cancel
|
||||
public int op;
|
||||
public ContentResolver resolver;
|
||||
public Uri uri;
|
||||
public String authority;
|
||||
public Handler handler;
|
||||
public String[] projection;
|
||||
public String selection;
|
||||
public String[] selectionArgs;
|
||||
public String orderBy;
|
||||
public Object result;
|
||||
public Object cookie;
|
||||
public ContentValues values;
|
||||
public ArrayList<ContentProviderOperation> cpo;
|
||||
|
||||
/**
|
||||
* delayMillis is relative time e.g. 10,000 milliseconds
|
||||
*/
|
||||
public long delayMillis;
|
||||
|
||||
/**
|
||||
* scheduleTimeMillis is the time scheduled for this to be processed.
|
||||
* e.g. SystemClock.elapsedRealtime() + 10,000 milliseconds Based on
|
||||
* {@link android.os.SystemClock#elapsedRealtime }
|
||||
*/
|
||||
private long mScheduledTimeMillis = 0;
|
||||
|
||||
// @VisibleForTesting
|
||||
void calculateScheduledTime() {
|
||||
mScheduledTimeMillis = SystemClock.elapsedRealtime() + delayMillis;
|
||||
}
|
||||
|
||||
// @Override // Uncomment with Java6
|
||||
public long getDelay(TimeUnit unit) {
|
||||
return unit.convert(mScheduledTimeMillis - SystemClock.elapsedRealtime(),
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
// @Override // Uncomment with Java6
|
||||
public int compareTo(Delayed another) {
|
||||
OperationInfo anotherArgs = (OperationInfo) another;
|
||||
if (this.mScheduledTimeMillis == anotherArgs.mScheduledTimeMillis) {
|
||||
return 0;
|
||||
} else if (this.mScheduledTimeMillis < anotherArgs.mScheduledTimeMillis) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("OperationInfo [\n\t token= ");
|
||||
builder.append(token);
|
||||
builder.append(",\n\t op= ");
|
||||
builder.append(Operation.opToChar(op));
|
||||
builder.append(",\n\t uri= ");
|
||||
builder.append(uri);
|
||||
builder.append(",\n\t authority= ");
|
||||
builder.append(authority);
|
||||
builder.append(",\n\t delayMillis= ");
|
||||
builder.append(delayMillis);
|
||||
builder.append(",\n\t mScheduledTimeMillis= ");
|
||||
builder.append(mScheduledTimeMillis);
|
||||
builder.append(",\n\t resolver= ");
|
||||
builder.append(resolver);
|
||||
builder.append(",\n\t handler= ");
|
||||
builder.append(handler);
|
||||
builder.append(",\n\t projection= ");
|
||||
builder.append(Arrays.toString(projection));
|
||||
builder.append(",\n\t selection= ");
|
||||
builder.append(selection);
|
||||
builder.append(",\n\t selectionArgs= ");
|
||||
builder.append(Arrays.toString(selectionArgs));
|
||||
builder.append(",\n\t orderBy= ");
|
||||
builder.append(orderBy);
|
||||
builder.append(",\n\t result= ");
|
||||
builder.append(result);
|
||||
builder.append(",\n\t cookie= ");
|
||||
builder.append(cookie);
|
||||
builder.append(",\n\t values= ");
|
||||
builder.append(values);
|
||||
builder.append(",\n\t cpo= ");
|
||||
builder.append(cpo);
|
||||
builder.append("\n]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares an user-visible operation to this private OperationInfo
|
||||
* object
|
||||
*
|
||||
* @param o operation to be compared
|
||||
* @return true if logically equivalent
|
||||
*/
|
||||
public boolean equivalent(Operation o) {
|
||||
return o.token == this.token && o.op == this.op;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
public class CalendarApplication extends Application {
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.backup.BackupAgentHelper;
|
||||
import android.app.backup.BackupDataInput;
|
||||
import android.app.backup.SharedPreferencesBackupHelper;
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentUris;
|
||||
@ -37,124 +35,35 @@ import com.android.colorpicker.HsvColorComparator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class CalendarColorPickerDialog extends ColorPickerDialog {
|
||||
|
||||
private static final int NUM_COLUMNS = 4;
|
||||
|
||||
private static final String KEY_CALENDAR_ID = "calendar_id";
|
||||
private static final String KEY_COLOR_KEYS = "color_keys";
|
||||
|
||||
private static final int TOKEN_QUERY_CALENDARS = 1 << 1;
|
||||
private static final int TOKEN_QUERY_COLORS = 1 << 2;
|
||||
|
||||
public static final int COLORS_INDEX_COLOR = 0;
|
||||
public static final int COLORS_INDEX_COLOR_KEY = 1;
|
||||
static final String[] CALENDARS_PROJECTION = new String[] {
|
||||
Calendars.ACCOUNT_NAME,
|
||||
Calendars.ACCOUNT_TYPE,
|
||||
Calendars.CALENDAR_COLOR
|
||||
};
|
||||
|
||||
static final int CALENDARS_INDEX_ACCOUNT_NAME = 0;
|
||||
static final int CALENDARS_INDEX_ACCOUNT_TYPE = 1;
|
||||
static final int CALENDARS_INDEX_CALENDAR_COLOR = 2;
|
||||
|
||||
static final String[] COLORS_PROJECTION = new String[] {
|
||||
Colors.COLOR,
|
||||
Colors.COLOR_KEY
|
||||
};
|
||||
|
||||
static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE +
|
||||
"=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_CALENDAR;
|
||||
|
||||
public static final int COLORS_INDEX_COLOR = 0;
|
||||
public static final int COLORS_INDEX_COLOR_KEY = 1;
|
||||
|
||||
|
||||
private static final int NUM_COLUMNS = 4;
|
||||
private static final String KEY_CALENDAR_ID = "calendar_id";
|
||||
private static final String KEY_COLOR_KEYS = "color_keys";
|
||||
private static final int TOKEN_QUERY_CALENDARS = 1 << 1;
|
||||
private static final int TOKEN_QUERY_COLORS = 1 << 2;
|
||||
private QueryService mService;
|
||||
private SparseIntArray mColorKeyMap = new SparseIntArray();
|
||||
private long mCalendarId;
|
||||
|
||||
private class QueryService extends AsyncQueryService {
|
||||
|
||||
private QueryService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
// If the query didn't return a cursor for some reason return
|
||||
if (cursor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the Activity is finishing, then close the cursor.
|
||||
// Otherwise, use the new cursor in the adapter.
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null || activity.isFinishing()) {
|
||||
cursor.close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (token) {
|
||||
case TOKEN_QUERY_CALENDARS:
|
||||
if (!cursor.moveToFirst()) {
|
||||
cursor.close();
|
||||
dismiss();
|
||||
break;
|
||||
}
|
||||
mSelectedColor = Utils.getDisplayColorFromColor(
|
||||
cursor.getInt(CALENDARS_INDEX_CALENDAR_COLOR));
|
||||
Uri uri = Colors.CONTENT_URI;
|
||||
String[] args = new String[] {
|
||||
cursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
|
||||
cursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) };
|
||||
cursor.close();
|
||||
startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE,
|
||||
args, null);
|
||||
break;
|
||||
case TOKEN_QUERY_COLORS:
|
||||
if (!cursor.moveToFirst()) {
|
||||
cursor.close();
|
||||
dismiss();
|
||||
break;
|
||||
}
|
||||
mColorKeyMap.clear();
|
||||
ArrayList<Integer> colors = new ArrayList<Integer>();
|
||||
do
|
||||
{
|
||||
int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
|
||||
int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
|
||||
int displayColor = Utils.getDisplayColorFromColor(rawColor);
|
||||
mColorKeyMap.put(displayColor, colorKey);
|
||||
colors.add(displayColor);
|
||||
} while (cursor.moveToNext());
|
||||
Integer[] colorsToSort = colors.toArray(new Integer[colors.size()]);
|
||||
Arrays.sort(colorsToSort, new HsvColorComparator());
|
||||
mColors = new int[colorsToSort.length];
|
||||
for (int i = 0; i < mColors.length; i++) {
|
||||
mColors[i] = colorsToSort[i];
|
||||
}
|
||||
showPaletteView();
|
||||
cursor.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OnCalendarColorSelectedListener implements OnColorSelectedListener {
|
||||
|
||||
@Override
|
||||
public void onColorSelected(int color) {
|
||||
if (color == mSelectedColor || mService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Calendars.CALENDAR_COLOR_KEY, mColorKeyMap.get(color));
|
||||
mService.startUpdate(mService.getNextToken(), null, ContentUris.withAppendedId(
|
||||
Calendars.CONTENT_URI, mCalendarId), values, null, null, Utils.UNDO_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
public CalendarColorPickerDialog() {
|
||||
// Empty constructor required for dialog fragments.
|
||||
}
|
||||
@ -236,4 +145,85 @@ public class CalendarColorPickerDialog extends ColorPickerDialog {
|
||||
CALENDARS_PROJECTION, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
private class QueryService extends AsyncQueryService {
|
||||
|
||||
private QueryService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
// If the query didn't return a cursor for some reason return
|
||||
if (cursor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the Activity is finishing, then close the cursor.
|
||||
// Otherwise, use the new cursor in the adapter.
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null || activity.isFinishing()) {
|
||||
cursor.close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (token) {
|
||||
case TOKEN_QUERY_CALENDARS:
|
||||
if (!cursor.moveToFirst()) {
|
||||
cursor.close();
|
||||
dismiss();
|
||||
break;
|
||||
}
|
||||
mSelectedColor = Utils.getDisplayColorFromColor(
|
||||
cursor.getInt(CALENDARS_INDEX_CALENDAR_COLOR));
|
||||
Uri uri = Colors.CONTENT_URI;
|
||||
String[] args = new String[]{
|
||||
cursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
|
||||
cursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE)};
|
||||
cursor.close();
|
||||
startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE,
|
||||
args, null);
|
||||
break;
|
||||
case TOKEN_QUERY_COLORS:
|
||||
if (!cursor.moveToFirst()) {
|
||||
cursor.close();
|
||||
dismiss();
|
||||
break;
|
||||
}
|
||||
mColorKeyMap.clear();
|
||||
ArrayList<Integer> colors = new ArrayList<Integer>();
|
||||
do {
|
||||
int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
|
||||
int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
|
||||
int displayColor = Utils.getDisplayColorFromColor(rawColor);
|
||||
mColorKeyMap.put(displayColor, colorKey);
|
||||
colors.add(displayColor);
|
||||
} while (cursor.moveToNext());
|
||||
Integer[] colorsToSort = colors.toArray(new Integer[colors.size()]);
|
||||
Arrays.sort(colorsToSort, new HsvColorComparator());
|
||||
mColors = new int[colorsToSort.length];
|
||||
for (int i = 0; i < mColors.length; i++) {
|
||||
mColors[i] = colorsToSort[i];
|
||||
}
|
||||
showPaletteView();
|
||||
cursor.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OnCalendarColorSelectedListener implements OnColorSelectedListener {
|
||||
|
||||
@Override
|
||||
public void onColorSelected(int color) {
|
||||
if (color == mSelectedColor || mService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Calendars.CALENDAR_COLOR_KEY, mColorKeyMap.get(color));
|
||||
mService.startUpdate(mService.getNextToken(), null, ContentUris.withAppendedId(
|
||||
Calendars.CONTENT_URI, mCalendarId), values, null, null, Utils.UNDO_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.Activity;
|
||||
@ -51,210 +44,22 @@ import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
||||
public class CalendarController {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "CalendarController";
|
||||
|
||||
public static final String EVENT_EDIT_ON_LAUNCH = "editMode";
|
||||
|
||||
public static final int MIN_CALENDAR_YEAR = 1970;
|
||||
public static final int MAX_CALENDAR_YEAR = 2036;
|
||||
public static final int MIN_CALENDAR_WEEK = 0;
|
||||
public static final int MAX_CALENDAR_WEEK = 3497; // weeks between 1/1/1970 and 1/1/2037
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
// This uses a LinkedHashMap so that we can replace fragments based on the
|
||||
// view id they are being expanded into since we can't guarantee a reference
|
||||
// to the handler will be findable
|
||||
private final LinkedHashMap<Integer,EventHandler> eventHandlers =
|
||||
new LinkedHashMap<Integer,EventHandler>(5);
|
||||
private final LinkedList<Integer> mToBeRemovedEventHandlers = new LinkedList<Integer>();
|
||||
private final LinkedHashMap<Integer, EventHandler> mToBeAddedEventHandlers = new LinkedHashMap<
|
||||
Integer, EventHandler>();
|
||||
private Pair<Integer, EventHandler> mFirstEventHandler;
|
||||
private Pair<Integer, EventHandler> mToBeAddedFirstEventHandler;
|
||||
private volatile int mDispatchInProgressCounter = 0;
|
||||
|
||||
private static WeakHashMap<Context, CalendarController> instances =
|
||||
new WeakHashMap<Context, CalendarController>();
|
||||
|
||||
private final WeakHashMap<Object, Long> filters = new WeakHashMap<Object, Long>(1);
|
||||
|
||||
private int mViewType = -1;
|
||||
private int mDetailViewType = -1;
|
||||
private int mPreviousViewType = -1;
|
||||
private long mEventId = -1;
|
||||
private final Time mTime = new Time();
|
||||
private long mDateFlags = 0;
|
||||
|
||||
private final Runnable mUpdateTimezone = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTime.switchTimezone(Utils.getTimeZone(mContext, this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* One of the event types that are sent to or from the controller
|
||||
*/
|
||||
public interface EventType {
|
||||
final long CREATE_EVENT = 1L;
|
||||
|
||||
// Simple view of an event
|
||||
final long VIEW_EVENT = 1L << 1;
|
||||
|
||||
// Full detail view in read only mode
|
||||
final long VIEW_EVENT_DETAILS = 1L << 2;
|
||||
|
||||
// full detail view in edit mode
|
||||
final long EDIT_EVENT = 1L << 3;
|
||||
|
||||
final long DELETE_EVENT = 1L << 4;
|
||||
|
||||
final long GO_TO = 1L << 5;
|
||||
|
||||
final long LAUNCH_SETTINGS = 1L << 6;
|
||||
|
||||
final long EVENTS_CHANGED = 1L << 7;
|
||||
|
||||
final long SEARCH = 1L << 8;
|
||||
|
||||
// User has pressed the home key
|
||||
final long USER_HOME = 1L << 9;
|
||||
|
||||
// date range has changed, update the title
|
||||
final long UPDATE_TITLE = 1L << 10;
|
||||
|
||||
// select which calendars to display
|
||||
final long LAUNCH_SELECT_VISIBLE_CALENDARS = 1L << 11;
|
||||
}
|
||||
|
||||
/**
|
||||
* One of the Agenda/Day/Week/Month view types
|
||||
*/
|
||||
public interface ViewType {
|
||||
final int DETAIL = -1;
|
||||
final int CURRENT = 0;
|
||||
final int AGENDA = 1;
|
||||
final int DAY = 2;
|
||||
final int WEEK = 3;
|
||||
final int MONTH = 4;
|
||||
final int EDIT = 5;
|
||||
final int MAX_VALUE = 5;
|
||||
}
|
||||
|
||||
public static class EventInfo {
|
||||
|
||||
private static final long ATTENTEE_STATUS_MASK = 0xFF;
|
||||
private static final long ALL_DAY_MASK = 0x100;
|
||||
private static final int ATTENDEE_STATUS_NONE_MASK = 0x01;
|
||||
private static final int ATTENDEE_STATUS_ACCEPTED_MASK = 0x02;
|
||||
private static final int ATTENDEE_STATUS_DECLINED_MASK = 0x04;
|
||||
private static final int ATTENDEE_STATUS_TENTATIVE_MASK = 0x08;
|
||||
|
||||
public long eventType; // one of the EventType
|
||||
public int viewType; // one of the ViewType
|
||||
public long id; // event id
|
||||
public Time selectedTime; // the selected time in focus
|
||||
|
||||
// Event start and end times. All-day events are represented in:
|
||||
// - local time for GO_TO commands
|
||||
// - UTC time for VIEW_EVENT and other event-related commands
|
||||
public Time startTime;
|
||||
public Time endTime;
|
||||
|
||||
public int x; // x coordinate in the activity space
|
||||
public int y; // y coordinate in the activity space
|
||||
public String query; // query for a user search
|
||||
public ComponentName componentName; // used in combination with query
|
||||
public String eventTitle;
|
||||
public long calendarId;
|
||||
|
||||
/**
|
||||
* For EventType.VIEW_EVENT:
|
||||
* It is the default attendee response and an all day event indicator.
|
||||
* Set to Attendees.ATTENDEE_STATUS_NONE, Attendees.ATTENDEE_STATUS_ACCEPTED,
|
||||
* Attendees.ATTENDEE_STATUS_DECLINED, or Attendees.ATTENDEE_STATUS_TENTATIVE.
|
||||
* To signal the event is an all-day event, "or" ALL_DAY_MASK with the response.
|
||||
* Alternatively, use buildViewExtraLong(), getResponse(), and isAllDay().
|
||||
* <p>
|
||||
* For EventType.CREATE_EVENT:
|
||||
* Set to {@link #EXTRA_CREATE_ALL_DAY} for creating an all-day event.
|
||||
* <p>
|
||||
* For EventType.GO_TO:
|
||||
* Set to {@link #EXTRA_GOTO_TIME} to go to the specified date/time.
|
||||
* Set to {@link #EXTRA_GOTO_DATE} to consider the date but ignore the time.
|
||||
* Set to {@link #EXTRA_GOTO_BACK_TO_PREVIOUS} if back should bring back previous view.
|
||||
* Set to {@link #EXTRA_GOTO_TODAY} if this is a user request to go to the current time.
|
||||
* <p>
|
||||
* For EventType.UPDATE_TITLE:
|
||||
* Set formatting flags for Utils.formatDateRange
|
||||
*/
|
||||
public long extraLong;
|
||||
|
||||
public boolean isAllDay() {
|
||||
if (eventType != EventType.VIEW_EVENT) {
|
||||
Log.wtf(TAG, "illegal call to isAllDay , wrong event type " + eventType);
|
||||
return false;
|
||||
}
|
||||
return ((extraLong & ALL_DAY_MASK) != 0) ? true : false;
|
||||
}
|
||||
|
||||
public int getResponse() {
|
||||
if (eventType != EventType.VIEW_EVENT) {
|
||||
Log.wtf(TAG, "illegal call to getResponse , wrong event type " + eventType);
|
||||
return Attendees.ATTENDEE_STATUS_NONE;
|
||||
}
|
||||
|
||||
int response = (int)(extraLong & ATTENTEE_STATUS_MASK);
|
||||
switch (response) {
|
||||
case ATTENDEE_STATUS_NONE_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_NONE;
|
||||
case ATTENDEE_STATUS_ACCEPTED_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_ACCEPTED;
|
||||
case ATTENDEE_STATUS_DECLINED_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
case ATTENDEE_STATUS_TENTATIVE_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_TENTATIVE;
|
||||
default:
|
||||
Log.wtf(TAG,"Unknown attendee response " + response);
|
||||
}
|
||||
return ATTENDEE_STATUS_NONE_MASK;
|
||||
}
|
||||
|
||||
// Used to build the extra long for a VIEW event.
|
||||
public static long buildViewExtraLong(int response, boolean allDay) {
|
||||
long extra = allDay ? ALL_DAY_MASK : 0;
|
||||
|
||||
switch (response) {
|
||||
case Attendees.ATTENDEE_STATUS_NONE:
|
||||
extra |= ATTENDEE_STATUS_NONE_MASK;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_ACCEPTED:
|
||||
extra |= ATTENDEE_STATUS_ACCEPTED_MASK;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_DECLINED:
|
||||
extra |= ATTENDEE_STATUS_DECLINED_MASK;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_TENTATIVE:
|
||||
extra |= ATTENDEE_STATUS_TENTATIVE_MASK;
|
||||
break;
|
||||
default:
|
||||
Log.wtf(TAG,"Unknown attendee response " + response);
|
||||
extra |= ATTENDEE_STATUS_NONE_MASK;
|
||||
break;
|
||||
}
|
||||
return extra;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass to the ExtraLong parameter for EventType.CREATE_EVENT to create
|
||||
* an all-day event
|
||||
*/
|
||||
public static final long EXTRA_CREATE_ALL_DAY = 0x10;
|
||||
|
||||
/**
|
||||
* Pass to the ExtraLong parameter for EventType.GO_TO to signal the time
|
||||
* can be ignored
|
||||
@ -263,16 +68,43 @@ public class CalendarController {
|
||||
public static final long EXTRA_GOTO_TIME = 2;
|
||||
public static final long EXTRA_GOTO_BACK_TO_PREVIOUS = 4;
|
||||
public static final long EXTRA_GOTO_TODAY = 8;
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "CalendarController";
|
||||
private static WeakHashMap<Context, CalendarController> instances =
|
||||
new WeakHashMap<Context, CalendarController>();
|
||||
private final Context mContext;
|
||||
// This uses a LinkedHashMap so that we can replace fragments based on the
|
||||
// view id they are being expanded into since we can't guarantee a reference
|
||||
// to the handler will be findable
|
||||
private final LinkedHashMap<Integer,EventHandler> eventHandlers =
|
||||
new LinkedHashMap<Integer,EventHandler>(5);
|
||||
private final LinkedList<Integer> mToBeRemovedEventHandlers = new LinkedList<Integer>();
|
||||
private final LinkedHashMap<Integer, EventHandler> mToBeAddedEventHandlers = new LinkedHashMap<
|
||||
Integer, EventHandler>();
|
||||
private final WeakHashMap<Object, Long> filters = new WeakHashMap<Object, Long>(1);
|
||||
private final Time mTime = new Time();
|
||||
private final Runnable mUpdateTimezone = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTime.switchTimezone(Utils.getTimeZone(mContext, this));
|
||||
}
|
||||
};
|
||||
private Pair<Integer, EventHandler> mFirstEventHandler;
|
||||
private Pair<Integer, EventHandler> mToBeAddedFirstEventHandler;
|
||||
private volatile int mDispatchInProgressCounter = 0;
|
||||
private int mViewType = -1;
|
||||
private int mDetailViewType = -1;
|
||||
private int mPreviousViewType = -1;
|
||||
private long mEventId = -1;
|
||||
private long mDateFlags = 0;
|
||||
|
||||
public interface EventHandler {
|
||||
long getSupportedEventTypes();
|
||||
void handleEvent(EventInfo event);
|
||||
|
||||
/**
|
||||
* This notifies the handler that the database has changed and it should
|
||||
* update its view.
|
||||
*/
|
||||
void eventsChanged();
|
||||
private CalendarController(Context context) {
|
||||
mContext = context;
|
||||
mUpdateTimezone.run();
|
||||
mTime.setToNow();
|
||||
mDetailViewType = Utils.getSharedPreference(mContext,
|
||||
GeneralPreferences.KEY_DETAILED_VIEW,
|
||||
GeneralPreferences.DEFAULT_DETAILED_VIEW);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -302,17 +134,8 @@ public class CalendarController {
|
||||
instances.remove(context);
|
||||
}
|
||||
|
||||
private CalendarController(Context context) {
|
||||
mContext = context;
|
||||
mUpdateTimezone.run();
|
||||
mTime.setToNow();
|
||||
mDetailViewType = Utils.getSharedPreference(mContext,
|
||||
GeneralPreferences.KEY_DETAILED_VIEW,
|
||||
GeneralPreferences.DEFAULT_DETAILED_VIEW);
|
||||
}
|
||||
|
||||
public void sendEventRelatedEvent(Object sender, long eventType, long eventId, long startMillis,
|
||||
long endMillis, int x, int y, long selectedMillis) {
|
||||
long endMillis, int x, int y, long selectedMillis) {
|
||||
// TODO: pass the real allDay status or at least a status that says we don't know the
|
||||
// status and have the receiver query the data.
|
||||
// The current use of this method for VIEW_EVENT is by the day view to show an EventInfo
|
||||
@ -337,9 +160,9 @@ public class CalendarController {
|
||||
* @param selectedMillis The time to specify as selected
|
||||
*/
|
||||
public void sendEventRelatedEventWithExtra(Object sender, long eventType, long eventId,
|
||||
long startMillis, long endMillis, int x, int y, long extraLong, long selectedMillis) {
|
||||
long startMillis, long endMillis, int x, int y, long extraLong, long selectedMillis) {
|
||||
sendEventRelatedEventWithExtraWithTitleWithCalendarId(sender, eventType, eventId,
|
||||
startMillis, endMillis, x, y, extraLong, selectedMillis, null, -1);
|
||||
startMillis, endMillis, x, y, extraLong, selectedMillis, null, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -359,8 +182,8 @@ public class CalendarController {
|
||||
* @param calendarId The id of the calendar which the event belongs to
|
||||
*/
|
||||
public void sendEventRelatedEventWithExtraWithTitleWithCalendarId(Object sender, long eventType,
|
||||
long eventId, long startMillis, long endMillis, int x, int y, long extraLong,
|
||||
long selectedMillis, String title, long calendarId) {
|
||||
long eventId, long startMillis, long endMillis, int x, int y, long extraLong,
|
||||
long selectedMillis, String title, long calendarId) {
|
||||
EventInfo info = new EventInfo();
|
||||
info.eventType = eventType;
|
||||
if (eventType == EventType.EDIT_EVENT || eventType == EventType.VIEW_EVENT_DETAILS) {
|
||||
@ -385,18 +208,19 @@ public class CalendarController {
|
||||
info.calendarId = calendarId;
|
||||
this.sendEvent(sender, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for sending non-calendar-event events
|
||||
*
|
||||
* @param sender object of the caller
|
||||
* @param sender object of the caller
|
||||
* @param eventType one of {@link EventType}
|
||||
* @param start start time
|
||||
* @param end end time
|
||||
* @param eventId event id
|
||||
* @param viewType {@link ViewType}
|
||||
* @param start start time
|
||||
* @param end end time
|
||||
* @param eventId event id
|
||||
* @param viewType {@link ViewType}
|
||||
*/
|
||||
public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId,
|
||||
int viewType) {
|
||||
int viewType) {
|
||||
sendEvent(sender, eventType, start, end, start, eventId, viewType, EXTRA_GOTO_TIME, null,
|
||||
null);
|
||||
}
|
||||
@ -405,13 +229,13 @@ public class CalendarController {
|
||||
* sendEvent() variant with extraLong, search query, and search component name.
|
||||
*/
|
||||
public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId,
|
||||
int viewType, long extraLong, String query, ComponentName componentName) {
|
||||
int viewType, long extraLong, String query, ComponentName componentName) {
|
||||
sendEvent(sender, eventType, start, end, start, eventId, viewType, extraLong, query,
|
||||
componentName);
|
||||
}
|
||||
|
||||
public void sendEvent(Object sender, long eventType, Time start, Time end, Time selected,
|
||||
long eventId, int viewType, long extraLong, String query, ComponentName componentName) {
|
||||
long eventId, int viewType, long extraLong, String query, ComponentName componentName) {
|
||||
EventInfo info = new EventInfo();
|
||||
info.eventType = eventType;
|
||||
info.startTime = start;
|
||||
@ -516,7 +340,7 @@ public class CalendarController {
|
||||
|
||||
boolean handled = false;
|
||||
synchronized (this) {
|
||||
mDispatchInProgressCounter ++;
|
||||
mDispatchInProgressCounter++;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "sendEvent: Dispatching to " + eventHandlers.size() + " handlers");
|
||||
@ -532,7 +356,7 @@ public class CalendarController {
|
||||
}
|
||||
}
|
||||
for (Iterator<Entry<Integer, EventHandler>> handlers =
|
||||
eventHandlers.entrySet().iterator(); handlers.hasNext();) {
|
||||
eventHandlers.entrySet().iterator(); handlers.hasNext(); ) {
|
||||
Entry<Integer, EventHandler> entry = handlers.next();
|
||||
int key = entry.getKey();
|
||||
if (mFirstEventHandler != null && key == mFirstEventHandler.first) {
|
||||
@ -550,7 +374,7 @@ public class CalendarController {
|
||||
}
|
||||
}
|
||||
|
||||
mDispatchInProgressCounter --;
|
||||
mDispatchInProgressCounter--;
|
||||
|
||||
if (mDispatchInProgressCounter == 0) {
|
||||
|
||||
@ -683,14 +507,6 @@ public class CalendarController {
|
||||
return mTime.toMillis(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the last set of date flags sent with
|
||||
* {@link EventType#UPDATE_TITLE}
|
||||
*/
|
||||
public long getDateFlags() {
|
||||
return mDateFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time this controller is currently pointed at
|
||||
*
|
||||
@ -700,6 +516,14 @@ public class CalendarController {
|
||||
mTime.set(millisTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the last set of date flags sent with
|
||||
* {@link EventType#UPDATE_TITLE}
|
||||
*/
|
||||
public long getDateFlags() {
|
||||
return mDateFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the last event ID the edit view was launched with
|
||||
*/
|
||||
@ -707,10 +531,20 @@ public class CalendarController {
|
||||
return mEventId;
|
||||
}
|
||||
|
||||
// Sets the eventId. Should only be used for initialization.
|
||||
public void setEventId(long eventId) {
|
||||
mEventId = eventId;
|
||||
}
|
||||
|
||||
public int getViewType() {
|
||||
return mViewType;
|
||||
}
|
||||
|
||||
// Forces the viewType. Should only be used for initialization.
|
||||
public void setViewType(int viewType) {
|
||||
mViewType = viewType;
|
||||
}
|
||||
|
||||
public int getPreviousViewType() {
|
||||
return mPreviousViewType;
|
||||
}
|
||||
@ -730,15 +564,15 @@ public class CalendarController {
|
||||
}
|
||||
|
||||
private void launchCreateEvent(long startMillis, long endMillis, boolean allDayEvent,
|
||||
String title, long calendarId) {
|
||||
String title, long calendarId) {
|
||||
Intent intent = generateCreateEventIntent(startMillis, endMillis, allDayEvent, title,
|
||||
calendarId);
|
||||
calendarId);
|
||||
mEventId = -1;
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
public Intent generateCreateEventIntent(long startMillis, long endMillis,
|
||||
boolean allDayEvent, String title, long calendarId) {
|
||||
boolean allDayEvent, String title, long calendarId) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setClass(mContext, EditEventActivity.class);
|
||||
intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis);
|
||||
@ -772,6 +606,17 @@ public class CalendarController {
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
private void launchDeleteEvent(long eventId, long startMillis, long endMillis) {
|
||||
launchDeleteEventAndFinish(null, eventId, startMillis, endMillis, -1);
|
||||
}
|
||||
|
||||
private void launchDeleteEventAndFinish(Activity parentActivity, long eventId, long startMillis,
|
||||
long endMillis, int deleteWhich) {
|
||||
DeleteEventHelper deleteEventHelper = new DeleteEventHelper(mContext, parentActivity,
|
||||
parentActivity != null /* exit when done */);
|
||||
deleteEventHelper.delete(startMillis, endMillis, eventId, deleteWhich);
|
||||
}
|
||||
|
||||
// private void launchAlerts() {
|
||||
// Intent intent = new Intent();
|
||||
// intent.setClass(mContext, AlertActivity.class);
|
||||
@ -779,20 +624,9 @@ public class CalendarController {
|
||||
// mContext.startActivity(intent);
|
||||
// }
|
||||
|
||||
private void launchDeleteEvent(long eventId, long startMillis, long endMillis) {
|
||||
launchDeleteEventAndFinish(null, eventId, startMillis, endMillis, -1);
|
||||
}
|
||||
|
||||
private void launchDeleteEventAndFinish(Activity parentActivity, long eventId, long startMillis,
|
||||
long endMillis, int deleteWhich) {
|
||||
DeleteEventHelper deleteEventHelper = new DeleteEventHelper(mContext, parentActivity,
|
||||
parentActivity != null /* exit when done */);
|
||||
deleteEventHelper.delete(startMillis, endMillis, eventId, deleteWhich);
|
||||
}
|
||||
|
||||
private void launchSearch(long eventId, String query, ComponentName componentName) {
|
||||
final SearchManager searchManager =
|
||||
(SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE);
|
||||
(SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
|
||||
final SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName);
|
||||
final Intent intent = new Intent(Intent.ACTION_SEARCH);
|
||||
intent.putExtra(SearchManager.QUERY, query);
|
||||
@ -819,16 +653,6 @@ public class CalendarController {
|
||||
}
|
||||
}
|
||||
|
||||
// Forces the viewType. Should only be used for initialization.
|
||||
public void setViewType(int viewType) {
|
||||
mViewType = viewType;
|
||||
}
|
||||
|
||||
// Sets the eventId. Should only be used for initialization.
|
||||
public void setEventId(long eventId) {
|
||||
mEventId = eventId;
|
||||
}
|
||||
|
||||
private String eventInfoToString(EventInfo eventInfo) {
|
||||
String tmp = "Unknown";
|
||||
|
||||
@ -875,4 +699,170 @@ public class CalendarController {
|
||||
builder.append(eventInfo.y);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* One of the event types that are sent to or from the controller
|
||||
*/
|
||||
public interface EventType {
|
||||
final long CREATE_EVENT = 1L;
|
||||
|
||||
// Simple view of an event
|
||||
final long VIEW_EVENT = 1L << 1;
|
||||
|
||||
// Full detail view in read only mode
|
||||
final long VIEW_EVENT_DETAILS = 1L << 2;
|
||||
|
||||
// full detail view in edit mode
|
||||
final long EDIT_EVENT = 1L << 3;
|
||||
|
||||
final long DELETE_EVENT = 1L << 4;
|
||||
|
||||
final long GO_TO = 1L << 5;
|
||||
|
||||
final long LAUNCH_SETTINGS = 1L << 6;
|
||||
|
||||
final long EVENTS_CHANGED = 1L << 7;
|
||||
|
||||
final long SEARCH = 1L << 8;
|
||||
|
||||
// User has pressed the home key
|
||||
final long USER_HOME = 1L << 9;
|
||||
|
||||
// date range has changed, update the title
|
||||
final long UPDATE_TITLE = 1L << 10;
|
||||
|
||||
// select which calendars to display
|
||||
final long LAUNCH_SELECT_VISIBLE_CALENDARS = 1L << 11;
|
||||
}
|
||||
|
||||
/**
|
||||
* One of the Agenda/Day/Week/Month view types
|
||||
*/
|
||||
public interface ViewType {
|
||||
final int DETAIL = -1;
|
||||
final int CURRENT = 0;
|
||||
final int AGENDA = 1;
|
||||
final int DAY = 2;
|
||||
final int WEEK = 3;
|
||||
final int MONTH = 4;
|
||||
final int EDIT = 5;
|
||||
final int MAX_VALUE = 5;
|
||||
}
|
||||
|
||||
public interface EventHandler {
|
||||
long getSupportedEventTypes();
|
||||
|
||||
void handleEvent(EventInfo event);
|
||||
|
||||
/**
|
||||
* This notifies the handler that the database has changed and it should
|
||||
* update its view.
|
||||
*/
|
||||
void eventsChanged();
|
||||
}
|
||||
|
||||
public static class EventInfo {
|
||||
|
||||
private static final long ATTENTEE_STATUS_MASK = 0xFF;
|
||||
private static final long ALL_DAY_MASK = 0x100;
|
||||
private static final int ATTENDEE_STATUS_NONE_MASK = 0x01;
|
||||
private static final int ATTENDEE_STATUS_ACCEPTED_MASK = 0x02;
|
||||
private static final int ATTENDEE_STATUS_DECLINED_MASK = 0x04;
|
||||
private static final int ATTENDEE_STATUS_TENTATIVE_MASK = 0x08;
|
||||
|
||||
public long eventType; // one of the EventType
|
||||
public int viewType; // one of the ViewType
|
||||
public long id; // event id
|
||||
public Time selectedTime; // the selected time in focus
|
||||
|
||||
// Event start and end times. All-day events are represented in:
|
||||
// - local time for GO_TO commands
|
||||
// - UTC time for VIEW_EVENT and other event-related commands
|
||||
public Time startTime;
|
||||
public Time endTime;
|
||||
|
||||
public int x; // x coordinate in the activity space
|
||||
public int y; // y coordinate in the activity space
|
||||
public String query; // query for a user search
|
||||
public ComponentName componentName; // used in combination with query
|
||||
public String eventTitle;
|
||||
public long calendarId;
|
||||
|
||||
/**
|
||||
* For EventType.VIEW_EVENT:
|
||||
* It is the default attendee response and an all day event indicator.
|
||||
* Set to Attendees.ATTENDEE_STATUS_NONE, Attendees.ATTENDEE_STATUS_ACCEPTED,
|
||||
* Attendees.ATTENDEE_STATUS_DECLINED, or Attendees.ATTENDEE_STATUS_TENTATIVE.
|
||||
* To signal the event is an all-day event, "or" ALL_DAY_MASK with the response.
|
||||
* Alternatively, use buildViewExtraLong(), getResponse(), and isAllDay().
|
||||
* <p/>
|
||||
* For EventType.CREATE_EVENT:
|
||||
* Set to {@link #EXTRA_CREATE_ALL_DAY} for creating an all-day event.
|
||||
* <p/>
|
||||
* For EventType.GO_TO:
|
||||
* Set to {@link #EXTRA_GOTO_TIME} to go to the specified date/time.
|
||||
* Set to {@link #EXTRA_GOTO_DATE} to consider the date but ignore the time.
|
||||
* Set to {@link #EXTRA_GOTO_BACK_TO_PREVIOUS} if back should bring back previous view.
|
||||
* Set to {@link #EXTRA_GOTO_TODAY} if this is a user request to go to the current time.
|
||||
* <p/>
|
||||
* For EventType.UPDATE_TITLE:
|
||||
* Set formatting flags for Utils.formatDateRange
|
||||
*/
|
||||
public long extraLong;
|
||||
|
||||
// Used to build the extra long for a VIEW event.
|
||||
public static long buildViewExtraLong(int response, boolean allDay) {
|
||||
long extra = allDay ? ALL_DAY_MASK : 0;
|
||||
|
||||
switch (response) {
|
||||
case Attendees.ATTENDEE_STATUS_NONE:
|
||||
extra |= ATTENDEE_STATUS_NONE_MASK;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_ACCEPTED:
|
||||
extra |= ATTENDEE_STATUS_ACCEPTED_MASK;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_DECLINED:
|
||||
extra |= ATTENDEE_STATUS_DECLINED_MASK;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_TENTATIVE:
|
||||
extra |= ATTENDEE_STATUS_TENTATIVE_MASK;
|
||||
break;
|
||||
default:
|
||||
Log.wtf(TAG, "Unknown attendee response " + response);
|
||||
extra |= ATTENDEE_STATUS_NONE_MASK;
|
||||
break;
|
||||
}
|
||||
return extra;
|
||||
}
|
||||
|
||||
public boolean isAllDay() {
|
||||
if (eventType != EventType.VIEW_EVENT) {
|
||||
Log.wtf(TAG, "illegal call to isAllDay , wrong event type " + eventType);
|
||||
return false;
|
||||
}
|
||||
return ((extraLong & ALL_DAY_MASK) != 0) ? true : false;
|
||||
}
|
||||
|
||||
public int getResponse() {
|
||||
if (eventType != EventType.VIEW_EVENT) {
|
||||
Log.wtf(TAG, "illegal call to getResponse , wrong event type " + eventType);
|
||||
return Attendees.ATTENDEE_STATUS_NONE;
|
||||
}
|
||||
|
||||
int response = (int) (extraLong & ATTENTEE_STATUS_MASK);
|
||||
switch (response) {
|
||||
case ATTENDEE_STATUS_NONE_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_NONE;
|
||||
case ATTENDEE_STATUS_ACCEPTED_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_ACCEPTED;
|
||||
case ATTENDEE_STATUS_DECLINED_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
case ATTENDEE_STATUS_TENTATIVE_MASK:
|
||||
return Attendees.ATTENDEE_STATUS_TENTATIVE;
|
||||
default:
|
||||
Log.wtf(TAG, "Unknown attendee response " + response);
|
||||
}
|
||||
return ATTENDEE_STATUS_NONE_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@ -46,180 +44,25 @@ import java.util.TimeZone;
|
||||
*/
|
||||
public class CalendarEventModel implements Serializable {
|
||||
private static final String TAG = "CalendarEventModel";
|
||||
|
||||
public static class Attendee implements Serializable {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (mEmail == null) ? 0 : mEmail.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Attendee)) {
|
||||
return false;
|
||||
}
|
||||
Attendee other = (Attendee) obj;
|
||||
if (!TextUtils.equals(mEmail, other.mEmail)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
String getDisplayName() {
|
||||
if (TextUtils.isEmpty(mName)) {
|
||||
return mEmail;
|
||||
} else {
|
||||
return mName;
|
||||
}
|
||||
}
|
||||
|
||||
public String mName;
|
||||
public String mEmail;
|
||||
public int mStatus;
|
||||
public String mIdentity;
|
||||
public String mIdNamespace;
|
||||
|
||||
public Attendee(String name, String email) {
|
||||
this(name, email, Attendees.ATTENDEE_STATUS_NONE, null, null);
|
||||
}
|
||||
public Attendee(String name, String email, int status, String identity,
|
||||
String idNamespace) {
|
||||
mName = name;
|
||||
mEmail = email;
|
||||
mStatus = status;
|
||||
mIdentity = identity;
|
||||
mIdNamespace = idNamespace;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single reminder entry.
|
||||
*
|
||||
* Instances of the class are immutable.
|
||||
*/
|
||||
public static class ReminderEntry implements Comparable<ReminderEntry>, Serializable {
|
||||
private final int mMinutes;
|
||||
private final int mMethod;
|
||||
|
||||
/**
|
||||
* Returns a new ReminderEntry, with the specified minutes and method.
|
||||
*
|
||||
* @param minutes Number of minutes before the start of the event that the alert will fire.
|
||||
* @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
|
||||
*/
|
||||
public static ReminderEntry valueOf(int minutes, int method) {
|
||||
// TODO: cache common instances
|
||||
return new ReminderEntry(minutes, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ReminderEntry, with the specified number of minutes and a default alert method.
|
||||
*
|
||||
* @param minutes Number of minutes before the start of the event that the alert will fire.
|
||||
*/
|
||||
public static ReminderEntry valueOf(int minutes) {
|
||||
return valueOf(minutes, Reminders.METHOD_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ReminderEntry.
|
||||
*
|
||||
* @param minutes Number of minutes before the start of the event that the alert will fire.
|
||||
* @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
|
||||
*/
|
||||
private ReminderEntry(int minutes, int method) {
|
||||
// TODO: error-check args
|
||||
mMinutes = minutes;
|
||||
mMethod = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mMinutes * 10 + mMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ReminderEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReminderEntry re = (ReminderEntry) obj;
|
||||
|
||||
if (re.mMinutes != mMinutes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Treat ALERT and DEFAULT as equivalent. This is useful during the "has anything
|
||||
// "changed" test, so that if DEFAULT is present, but we don't change anything,
|
||||
// the internal conversion of DEFAULT to ALERT doesn't force a database update.
|
||||
return re.mMethod == mMethod ||
|
||||
(re.mMethod == Reminders.METHOD_DEFAULT && mMethod == Reminders.METHOD_ALERT) ||
|
||||
(re.mMethod == Reminders.METHOD_ALERT && mMethod == Reminders.METHOD_DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReminderEntry min=" + mMinutes + " meth=" + mMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison function for a sort ordered primarily descending by minutes,
|
||||
* secondarily ascending by method type.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(ReminderEntry re) {
|
||||
if (re.mMinutes != mMinutes) {
|
||||
return re.mMinutes - mMinutes;
|
||||
}
|
||||
if (re.mMethod != mMethod) {
|
||||
return mMethod - re.mMethod;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the minutes. */
|
||||
public int getMinutes() {
|
||||
return mMinutes;
|
||||
}
|
||||
|
||||
/** Returns the alert method. */
|
||||
public int getMethod() {
|
||||
return mMethod;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO strip out fields that don't ever get used
|
||||
/**
|
||||
* The uri of the event in the db. This should only be null for new events.
|
||||
*/
|
||||
public String mUri = null;
|
||||
public long mId = -1;
|
||||
|
||||
// TODO strip out fields that don't ever get used
|
||||
public long mCalendarId = -1;
|
||||
public String mCalendarDisplayName = ""; // Make sure this is in sync with the mCalendarId
|
||||
private int mCalendarColor = -1;
|
||||
private boolean mCalendarColorInitialized = false;
|
||||
public String mCalendarAccountName;
|
||||
public String mCalendarAccountType;
|
||||
public int mCalendarMaxReminders;
|
||||
public String mCalendarAllowedReminders;
|
||||
public String mCalendarAllowedAttendeeTypes;
|
||||
public String mCalendarAllowedAvailability;
|
||||
|
||||
public String mSyncId = null;
|
||||
public String mSyncAccount = null;
|
||||
public String mSyncAccountType = null;
|
||||
|
||||
public EventColorCache mEventColorCache;
|
||||
private int mEventColor = -1;
|
||||
private boolean mEventColorInitialized = false;
|
||||
|
||||
// PROVIDER_NOTES owner account comes from the calendars table
|
||||
public String mOwnerAccount = null;
|
||||
public String mTitle = null;
|
||||
@ -233,12 +76,10 @@ public class CalendarEventModel implements Serializable {
|
||||
*/
|
||||
public boolean mIsOrganizer = true;
|
||||
public boolean mIsFirstEventInSeries = true;
|
||||
|
||||
// This should be set the same as mStart when created and is used for making changes to
|
||||
// recurring events. It should not be updated after it is initially set.
|
||||
public long mOriginalStart = -1;
|
||||
public long mStart = -1;
|
||||
|
||||
// This should be set the same as mEnd when created and is used for making changes to
|
||||
// recurring events. It should not be updated after it is initially set.
|
||||
public long mOriginalEnd = -1;
|
||||
@ -249,7 +90,6 @@ public class CalendarEventModel implements Serializable {
|
||||
public boolean mAllDay = false;
|
||||
public boolean mHasAlarm = false;
|
||||
public int mAvailability = Events.AVAILABILITY_BUSY;
|
||||
|
||||
// PROVIDER_NOTES How does an event not have attendee data? The owner is added
|
||||
// as an attendee by default.
|
||||
public boolean mHasAttendeeData = true;
|
||||
@ -262,24 +102,22 @@ public class CalendarEventModel implements Serializable {
|
||||
public boolean mGuestsCanModify = false;
|
||||
public boolean mGuestsCanInviteOthers = false;
|
||||
public boolean mGuestsCanSeeGuests = false;
|
||||
|
||||
public boolean mOrganizerCanRespond = false;
|
||||
public int mCalendarAccessLevel = Calendars.CAL_ACCESS_CONTRIBUTOR;
|
||||
|
||||
public int mEventStatus = Events.STATUS_CONFIRMED;
|
||||
|
||||
// The model can't be updated with a calendar cursor until it has been
|
||||
// updated with an event cursor.
|
||||
public boolean mModelUpdatedWithEventCursor;
|
||||
|
||||
public int mAccessLevel = 0;
|
||||
public ArrayList<ReminderEntry> mReminders;
|
||||
public ArrayList<ReminderEntry> mDefaultReminders;
|
||||
|
||||
// PROVIDER_NOTES Using EditEventHelper the owner should not be included in this
|
||||
// list and will instead be added by saveEvent. Is this what we want?
|
||||
public LinkedHashMap<String, Attendee> mAttendeesList;
|
||||
|
||||
private int mCalendarColor = -1;
|
||||
private boolean mCalendarColorInitialized = false;
|
||||
private int mEventColor = -1;
|
||||
private boolean mEventColorInitialized = false;
|
||||
public CalendarEventModel() {
|
||||
mReminders = new ArrayList<ReminderEntry>();
|
||||
mDefaultReminders = new ArrayList<ReminderEntry>();
|
||||
@ -915,15 +753,15 @@ public class CalendarEventModel implements Serializable {
|
||||
return mCalendarColor;
|
||||
}
|
||||
|
||||
public int getEventColor() {
|
||||
return mEventColor;
|
||||
}
|
||||
|
||||
public void setCalendarColor(int color) {
|
||||
mCalendarColor = color;
|
||||
mCalendarColorInitialized = true;
|
||||
}
|
||||
|
||||
public int getEventColor() {
|
||||
return mEventColor;
|
||||
}
|
||||
|
||||
public void setEventColor(int color) {
|
||||
mEventColor = color;
|
||||
mEventColorInitialized = true;
|
||||
@ -943,4 +781,153 @@ public class CalendarEventModel implements Serializable {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static class Attendee implements Serializable {
|
||||
public String mName;
|
||||
public String mEmail;
|
||||
public int mStatus;
|
||||
public String mIdentity;
|
||||
public String mIdNamespace;
|
||||
|
||||
public Attendee(String name, String email) {
|
||||
this(name, email, Attendees.ATTENDEE_STATUS_NONE, null, null);
|
||||
}
|
||||
|
||||
public Attendee(String name, String email, int status, String identity,
|
||||
String idNamespace) {
|
||||
mName = name;
|
||||
mEmail = email;
|
||||
mStatus = status;
|
||||
mIdentity = identity;
|
||||
mIdNamespace = idNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (mEmail == null) ? 0 : mEmail.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Attendee)) {
|
||||
return false;
|
||||
}
|
||||
Attendee other = (Attendee) obj;
|
||||
if (!TextUtils.equals(mEmail, other.mEmail)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
String getDisplayName() {
|
||||
if (TextUtils.isEmpty(mName)) {
|
||||
return mEmail;
|
||||
} else {
|
||||
return mName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single reminder entry.
|
||||
* <p/>
|
||||
* Instances of the class are immutable.
|
||||
*/
|
||||
public static class ReminderEntry implements Comparable<ReminderEntry>, Serializable {
|
||||
private final int mMinutes;
|
||||
private final int mMethod;
|
||||
|
||||
/**
|
||||
* Constructs a new ReminderEntry.
|
||||
*
|
||||
* @param minutes Number of minutes before the start of the event that the alert will fire.
|
||||
* @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
|
||||
*/
|
||||
private ReminderEntry(int minutes, int method) {
|
||||
// TODO: error-check args
|
||||
mMinutes = minutes;
|
||||
mMethod = method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new ReminderEntry, with the specified minutes and method.
|
||||
*
|
||||
* @param minutes Number of minutes before the start of the event that the alert will fire.
|
||||
* @param method Type of alert ({@link Reminders#METHOD_ALERT}, etc).
|
||||
*/
|
||||
public static ReminderEntry valueOf(int minutes, int method) {
|
||||
// TODO: cache common instances
|
||||
return new ReminderEntry(minutes, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ReminderEntry, with the specified number of minutes and a default alert method.
|
||||
*
|
||||
* @param minutes Number of minutes before the start of the event that the alert will fire.
|
||||
*/
|
||||
public static ReminderEntry valueOf(int minutes) {
|
||||
return valueOf(minutes, Reminders.METHOD_DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mMinutes * 10 + mMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ReminderEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReminderEntry re = (ReminderEntry) obj;
|
||||
|
||||
if (re.mMinutes != mMinutes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Treat ALERT and DEFAULT as equivalent. This is useful during the "has anything
|
||||
// "changed" test, so that if DEFAULT is present, but we don't change anything,
|
||||
// the internal conversion of DEFAULT to ALERT doesn't force a database update.
|
||||
return re.mMethod == mMethod ||
|
||||
(re.mMethod == Reminders.METHOD_DEFAULT && mMethod == Reminders.METHOD_ALERT) ||
|
||||
(re.mMethod == Reminders.METHOD_ALERT && mMethod == Reminders.METHOD_DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReminderEntry min=" + mMinutes + " meth=" + mMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison function for a sort ordered primarily descending by minutes,
|
||||
* secondarily ascending by method type.
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(ReminderEntry re) {
|
||||
if (re.mMinutes != mMinutes) {
|
||||
return re.mMinutes - mMinutes;
|
||||
}
|
||||
if (re.mMethod != mMethod) {
|
||||
return mMethod - re.mMethod;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the minutes. */
|
||||
public int getMinutes() {
|
||||
return mMinutes;
|
||||
}
|
||||
|
||||
/** Returns the alert method. */
|
||||
public int getMethod() {
|
||||
return mMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.SearchRecentSuggestionsProvider;
|
||||
|
||||
public class CalendarRecentSuggestionsProvider extends SearchRecentSuggestionsProvider {
|
||||
|
@ -37,10 +37,10 @@ import android.widget.LinearLayout;
|
||||
|
||||
import com.android.calendar.selectcalendars.SelectCalendarsSyncFragment;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class CalendarSettingsActivity extends PreferenceActivity {
|
||||
private static final int CHECK_ACCOUNTS_DELAY = 3000;
|
||||
private Account[] mAccounts;
|
||||
|
@ -8,11 +8,11 @@ import android.text.format.DateUtils;
|
||||
import android.text.format.Time;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* Created by xsoh64 on 7/21/15.
|
||||
*/
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
@ -43,34 +41,51 @@ public class CalendarUtils {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "CalendarUtils";
|
||||
|
||||
/**
|
||||
* A helper method for writing a String value to the preferences
|
||||
* asynchronously.
|
||||
*
|
||||
* @param context A context with access to the correct preferences
|
||||
* @param key The preference to write to
|
||||
* @param value The value to write
|
||||
*/
|
||||
public static void setSharedPreference(SharedPreferences prefs, String key, String value) {
|
||||
// SharedPreferences prefs = getSharedPreferences(context);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for writing a boolean value to the preferences
|
||||
* asynchronously.
|
||||
*
|
||||
* @param context A context with access to the correct preferences
|
||||
* @param key The preference to write to
|
||||
* @param value The value to write
|
||||
*/
|
||||
public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) {
|
||||
// SharedPreferences prefs = getSharedPreferences(context, prefsName);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a properly configured SharedPreferences instance
|
||||
*/
|
||||
public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
|
||||
return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class contains methods specific to reading and writing time zone
|
||||
* values.
|
||||
*/
|
||||
public static class TimeZoneUtils {
|
||||
private static final String[] TIMEZONE_TYPE_ARGS = { CalendarCache.KEY_TIMEZONE_TYPE };
|
||||
private static final String[] TIMEZONE_INSTANCES_ARGS =
|
||||
{ CalendarCache.KEY_TIMEZONE_INSTANCES };
|
||||
public static final String[] CALENDAR_CACHE_POJECTION = {
|
||||
CalendarCache.KEY, CalendarCache.VALUE
|
||||
};
|
||||
|
||||
private static StringBuilder mSB = new StringBuilder(50);
|
||||
private static Formatter mF = new Formatter(mSB, Locale.getDefault());
|
||||
private volatile static boolean mFirstTZRequest = true;
|
||||
private volatile static boolean mTZQueryInProgress = false;
|
||||
|
||||
private volatile static boolean mUseHomeTZ = false;
|
||||
private volatile static String mHomeTZ = Time.getCurrentTimezone();
|
||||
|
||||
private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
|
||||
private static int mToken = 1;
|
||||
private static AsyncTZHandler mHandler;
|
||||
|
||||
// The name of the shared preferences file. This name must be maintained for historical
|
||||
// reasons, as it's what PreferenceManager assigned the first time the file was created.
|
||||
private final String mPrefsName;
|
||||
|
||||
/**
|
||||
* This is the key used for writing whether or not a home time zone should
|
||||
* be used in the Calendar app to the Calendar Preferences.
|
||||
@ -81,65 +96,21 @@ public class CalendarUtils {
|
||||
* home time zones are enabled for the Calendar app.
|
||||
*/
|
||||
public static final String KEY_HOME_TZ = "preferences_home_tz";
|
||||
|
||||
/**
|
||||
* This is a helper class for handling the async queries and updates for the
|
||||
* time zone settings in Calendar.
|
||||
*/
|
||||
private class AsyncTZHandler extends AsyncQueryHandler {
|
||||
public AsyncTZHandler(ContentResolver cr) {
|
||||
super(cr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
synchronized (mTZCallbacks) {
|
||||
if (cursor == null) {
|
||||
mTZQueryInProgress = false;
|
||||
mFirstTZRequest = true;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean writePrefs = false;
|
||||
// Check the values in the db
|
||||
int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
|
||||
int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
|
||||
while(cursor.moveToNext()) {
|
||||
String key = cursor.getString(keyColumn);
|
||||
String value = cursor.getString(valueColumn);
|
||||
if (TextUtils.equals(key, CalendarCache.KEY_TIMEZONE_TYPE)) {
|
||||
boolean useHomeTZ = !TextUtils.equals(
|
||||
value, CalendarCache.TIMEZONE_TYPE_AUTO);
|
||||
if (useHomeTZ != mUseHomeTZ) {
|
||||
writePrefs = true;
|
||||
mUseHomeTZ = useHomeTZ;
|
||||
}
|
||||
} else if (TextUtils.equals(
|
||||
key, CalendarCache.KEY_TIMEZONE_INSTANCES_PREVIOUS)) {
|
||||
if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) {
|
||||
writePrefs = true;
|
||||
mHomeTZ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
if (writePrefs) {
|
||||
SharedPreferences prefs = getSharedPreferences((Context)cookie, mPrefsName);
|
||||
// Write the prefs
|
||||
setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
|
||||
setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
|
||||
}
|
||||
|
||||
mTZQueryInProgress = false;
|
||||
for (Runnable callback : mTZCallbacks) {
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
mTZCallbacks.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
private static final String[] TIMEZONE_TYPE_ARGS = {CalendarCache.KEY_TIMEZONE_TYPE};
|
||||
private static final String[] TIMEZONE_INSTANCES_ARGS =
|
||||
{CalendarCache.KEY_TIMEZONE_INSTANCES};
|
||||
private static StringBuilder mSB = new StringBuilder(50);
|
||||
private static Formatter mF = new Formatter(mSB, Locale.getDefault());
|
||||
private volatile static boolean mFirstTZRequest = true;
|
||||
private volatile static boolean mTZQueryInProgress = false;
|
||||
private volatile static boolean mUseHomeTZ = false;
|
||||
private volatile static String mHomeTZ = Time.getCurrentTimezone();
|
||||
private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
|
||||
private static int mToken = 1;
|
||||
private static AsyncTZHandler mHandler;
|
||||
// The name of the shared preferences file. This name must be maintained for historical
|
||||
// reasons, as it's what PreferenceManager assigned the first time the file was created.
|
||||
private final String mPrefsName;
|
||||
|
||||
/**
|
||||
* The name of the file where the shared prefs for Calendar are stored
|
||||
@ -315,40 +286,64 @@ public class CalendarUtils {
|
||||
getTimeZone(context, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper class for handling the async queries and updates for the
|
||||
* time zone settings in Calendar.
|
||||
*/
|
||||
private class AsyncTZHandler extends AsyncQueryHandler {
|
||||
public AsyncTZHandler(ContentResolver cr) {
|
||||
super(cr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
synchronized (mTZCallbacks) {
|
||||
if (cursor == null) {
|
||||
mTZQueryInProgress = false;
|
||||
mFirstTZRequest = true;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean writePrefs = false;
|
||||
// Check the values in the db
|
||||
int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
|
||||
int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
|
||||
while (cursor.moveToNext()) {
|
||||
String key = cursor.getString(keyColumn);
|
||||
String value = cursor.getString(valueColumn);
|
||||
if (TextUtils.equals(key, CalendarCache.KEY_TIMEZONE_TYPE)) {
|
||||
boolean useHomeTZ = !TextUtils.equals(
|
||||
value, CalendarCache.TIMEZONE_TYPE_AUTO);
|
||||
if (useHomeTZ != mUseHomeTZ) {
|
||||
writePrefs = true;
|
||||
mUseHomeTZ = useHomeTZ;
|
||||
}
|
||||
} else if (TextUtils.equals(
|
||||
key, CalendarCache.KEY_TIMEZONE_INSTANCES_PREVIOUS)) {
|
||||
if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) {
|
||||
writePrefs = true;
|
||||
mHomeTZ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
if (writePrefs) {
|
||||
SharedPreferences prefs = getSharedPreferences((Context) cookie, mPrefsName);
|
||||
// Write the prefs
|
||||
setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
|
||||
setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
|
||||
}
|
||||
|
||||
mTZQueryInProgress = false;
|
||||
for (Runnable callback : mTZCallbacks) {
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
mTZCallbacks.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for writing a String value to the preferences
|
||||
* asynchronously.
|
||||
*
|
||||
* @param context A context with access to the correct preferences
|
||||
* @param key The preference to write to
|
||||
* @param value The value to write
|
||||
*/
|
||||
public static void setSharedPreference(SharedPreferences prefs, String key, String value) {
|
||||
// SharedPreferences prefs = getSharedPreferences(context);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for writing a boolean value to the preferences
|
||||
* asynchronously.
|
||||
*
|
||||
* @param context A context with access to the correct preferences
|
||||
* @param key The preference to write to
|
||||
* @param value The value to write
|
||||
*/
|
||||
public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) {
|
||||
// SharedPreferences prefs = getSharedPreferences(context, prefsName);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
/** Return a properly configured SharedPreferences instance */
|
||||
public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
|
||||
return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.text.format.DateUtils;
|
||||
@ -30,9 +26,13 @@ import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
|
||||
/*
|
||||
* The MenuSpinnerAdapter defines the look of the ActionBar's pull down menu
|
||||
@ -43,40 +43,32 @@ import java.util.Locale;
|
||||
|
||||
public class CalendarViewAdapter extends BaseAdapter {
|
||||
|
||||
public static final int DAY_BUTTON_INDEX = 0;
|
||||
public static final int WEEK_BUTTON_INDEX = 1;
|
||||
public static final int MONTH_BUTTON_INDEX = 2;
|
||||
public static final int AGENDA_BUTTON_INDEX = 3;
|
||||
static final int VIEW_TYPE_NUM = 1; // Increase this if you add more view types
|
||||
private static final String TAG = "MenuSpinnerAdapter";
|
||||
|
||||
// Defines the types of view returned by this spinner
|
||||
private static final int BUTTON_VIEW_TYPE = 0;
|
||||
private final String mButtonNames []; // Text on buttons
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final Context mContext;
|
||||
private final Formatter mFormatter;
|
||||
private final StringBuilder mStringBuilder;
|
||||
private final boolean mShowDate; // Spinner mode indicator (view name or view name with date)
|
||||
// Used to define the look of the menu button according to the current view:
|
||||
// Day view: show day of the week + full date underneath
|
||||
// Week view: show the month + year
|
||||
// Month view: show the month + year
|
||||
// Agenda view: show day of the week + full date underneath
|
||||
private int mCurrentMainView;
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
|
||||
// Defines the types of view returned by this spinner
|
||||
private static final int BUTTON_VIEW_TYPE = 0;
|
||||
static final int VIEW_TYPE_NUM = 1; // Increase this if you add more view types
|
||||
|
||||
public static final int DAY_BUTTON_INDEX = 0;
|
||||
public static final int WEEK_BUTTON_INDEX = 1;
|
||||
public static final int MONTH_BUTTON_INDEX = 2;
|
||||
public static final int AGENDA_BUTTON_INDEX = 3;
|
||||
|
||||
// The current selected event's time, used to calculate the date and day of the week
|
||||
// for the buttons.
|
||||
private long mMilliTime;
|
||||
private String mTimeZone;
|
||||
private long mTodayJulianDay;
|
||||
|
||||
private final Context mContext;
|
||||
private final Formatter mFormatter;
|
||||
private final StringBuilder mStringBuilder;
|
||||
private Handler mMidnightHandler = null; // Used to run a time update every midnight
|
||||
private final boolean mShowDate; // Spinner mode indicator (view name or view name with date)
|
||||
|
||||
// Updates time specific variables (time-zone, today's Julian day).
|
||||
private final Runnable mTimeUpdater = new Runnable() {
|
||||
@Override
|
||||
|
@ -16,13 +16,11 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface CloudNotificationBackplane {
|
||||
public boolean open(Context context);
|
||||
public boolean subscribeToGroup(String senderId, String account, String groupId)
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
@ -35,26 +33,21 @@ import android.view.View;
|
||||
*/
|
||||
public class ColorChipView extends View {
|
||||
|
||||
private static final String TAG = "ColorChipView";
|
||||
public static final int DRAW_FULL = 0;
|
||||
// Style of drawing
|
||||
// Full rectangle for accepted events
|
||||
// Border for tentative events
|
||||
// Cross-hatched with 50% transparency for declined events
|
||||
|
||||
public static final int DRAW_FULL = 0;
|
||||
public static final int DRAW_BORDER = 1;
|
||||
public static final int DRAW_FADED = 2;
|
||||
|
||||
private static final String TAG = "ColorChipView";
|
||||
private static final int DEF_BORDER_WIDTH = 4;
|
||||
int mBorderWidth = DEF_BORDER_WIDTH;
|
||||
int mColor;
|
||||
private int mDrawStyle = DRAW_FULL;
|
||||
private float mDefStrokeWidth;
|
||||
private Paint mPaint;
|
||||
|
||||
private static final int DEF_BORDER_WIDTH = 4;
|
||||
|
||||
int mBorderWidth = DEF_BORDER_WIDTH;
|
||||
|
||||
int mColor;
|
||||
|
||||
public ColorChipView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.calendar.event.EditEventHelper.AttendeeItem;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
@ -32,6 +28,8 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.android.calendar.event.EditEventHelper.AttendeeItem;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
@ -41,87 +39,14 @@ public class ContactsAsyncHelper extends Handler {
|
||||
|
||||
private static final boolean DBG = false;
|
||||
private static final String LOG_TAG = "ContactsAsyncHelper";
|
||||
|
||||
private static ContactsAsyncHelper mInstance = null;
|
||||
|
||||
/**
|
||||
* Interface for a WorkerHandler result return.
|
||||
*/
|
||||
public interface OnImageLoadCompleteListener {
|
||||
/**
|
||||
* Called when the image load is complete.
|
||||
*
|
||||
* @param imagePresent true if an image was found
|
||||
*/
|
||||
public void onImageLoadComplete(int token, Object cookie, ImageView iView,
|
||||
boolean imagePresent);
|
||||
}
|
||||
|
||||
// constants
|
||||
private static final int EVENT_LOAD_IMAGE = 1;
|
||||
private static final int EVENT_LOAD_DRAWABLE = 2;
|
||||
private static final int DEFAULT_TOKEN = -1;
|
||||
|
||||
private static ContactsAsyncHelper mInstance = null;
|
||||
// static objects
|
||||
private static Handler sThreadHandler;
|
||||
|
||||
private static final class WorkerArgs {
|
||||
public Context context;
|
||||
public ImageView view;
|
||||
public Uri uri;
|
||||
public int defaultResource;
|
||||
public Object result;
|
||||
public AttendeeItem item;
|
||||
public Runnable callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread worker class that handles the task of opening the stream and loading
|
||||
* the images.
|
||||
*/
|
||||
private class WorkerHandler extends Handler {
|
||||
public WorkerHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
WorkerArgs args = (WorkerArgs) msg.obj;
|
||||
|
||||
switch (msg.arg1) {
|
||||
case EVENT_LOAD_DRAWABLE:
|
||||
case EVENT_LOAD_IMAGE:
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = Contacts.openContactPhotoInputStream(
|
||||
args.context.getContentResolver(), args.uri);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error opening photo input stream", e);
|
||||
}
|
||||
|
||||
if (inputStream != null) {
|
||||
args.result = Drawable.createFromStream(inputStream, args.uri.toString());
|
||||
|
||||
if (DBG) Log.d(LOG_TAG, "Loading image: " + msg.arg1 +
|
||||
" token: " + msg.what + " image URI: " + args.uri);
|
||||
} else {
|
||||
args.result = null;
|
||||
if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
|
||||
" token: " + msg.what + " image URI: " + args.uri +
|
||||
", using default image.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
// send the reply to the enclosing class.
|
||||
Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
|
||||
reply.arg1 = msg.arg1;
|
||||
reply.obj = msg.obj;
|
||||
reply.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for static class
|
||||
*/
|
||||
@ -252,4 +177,74 @@ public class ContactsAsyncHelper extends Handler {
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for a WorkerHandler result return.
|
||||
*/
|
||||
public interface OnImageLoadCompleteListener {
|
||||
/**
|
||||
* Called when the image load is complete.
|
||||
*
|
||||
* @param imagePresent true if an image was found
|
||||
*/
|
||||
public void onImageLoadComplete(int token, Object cookie, ImageView iView,
|
||||
boolean imagePresent);
|
||||
}
|
||||
|
||||
private static final class WorkerArgs {
|
||||
public Context context;
|
||||
public ImageView view;
|
||||
public Uri uri;
|
||||
public int defaultResource;
|
||||
public Object result;
|
||||
public AttendeeItem item;
|
||||
public Runnable callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread worker class that handles the task of opening the stream and loading
|
||||
* the images.
|
||||
*/
|
||||
private class WorkerHandler extends Handler {
|
||||
public WorkerHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
WorkerArgs args = (WorkerArgs) msg.obj;
|
||||
|
||||
switch (msg.arg1) {
|
||||
case EVENT_LOAD_DRAWABLE:
|
||||
case EVENT_LOAD_IMAGE:
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = Contacts.openContactPhotoInputStream(
|
||||
args.context.getContentResolver(), args.uri);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error opening photo input stream", e);
|
||||
}
|
||||
|
||||
if (inputStream != null) {
|
||||
args.result = Drawable.createFromStream(inputStream, args.uri.toString());
|
||||
|
||||
if (DBG) Log.d(LOG_TAG, "Loading image: " + msg.arg1 +
|
||||
" token: " + msg.what + " image URI: " + args.uri);
|
||||
} else {
|
||||
args.result = null;
|
||||
if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
|
||||
" token: " + msg.what + " image URI: " + args.uri +
|
||||
", using default image.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
// send the reply to the enclosing class.
|
||||
Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
|
||||
reply.arg1 = msg.arg1;
|
||||
reply.obj = msg.obj;
|
||||
reply.sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.calendar.CalendarController.EventInfo;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
@ -35,19 +30,22 @@ import android.widget.ProgressBar;
|
||||
import android.widget.ViewSwitcher;
|
||||
import android.widget.ViewSwitcher.ViewFactory;
|
||||
|
||||
import com.android.calendar.CalendarController.EventInfo;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* This is the base class for Day and Week Activities.
|
||||
*/
|
||||
public class DayFragment extends Fragment implements CalendarController.EventHandler, ViewFactory {
|
||||
protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
|
||||
/**
|
||||
* The view id used for all the views we create. It's OK to have all child
|
||||
* views have the same ID. This ID is used to pick which view receives
|
||||
* focus when a view hierarchy is saved / restore
|
||||
*/
|
||||
private static final int VIEW_ID = 1;
|
||||
|
||||
protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
|
||||
|
||||
protected ProgressBar mProgressBar;
|
||||
protected ViewSwitcher mViewSwitcher;
|
||||
protected Animation mInAnimationForward;
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.util.MonthDisplayHelper;
|
||||
|
||||
/**
|
||||
@ -73,6 +71,11 @@ public class DayOfMonthCursor extends MonthDisplayHelper {
|
||||
return getDayAt(mRow, mColumn);
|
||||
}
|
||||
|
||||
public void setSelectedDayOfMonth(int dayOfMonth) {
|
||||
mRow = getRowOf(dayOfMonth);
|
||||
mColumn = getColumnOf(dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if the selection is in the current month, otherwise -1 or +1
|
||||
* depending on whether the selection is in the first or last row.
|
||||
@ -87,11 +90,6 @@ public class DayOfMonthCursor extends MonthDisplayHelper {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void setSelectedDayOfMonth(int dayOfMonth) {
|
||||
mRow = getRowOf(dayOfMonth);
|
||||
mColumn = getColumnOf(dayOfMonth);
|
||||
}
|
||||
|
||||
public boolean isSelected(int row, int column) {
|
||||
return (mRow == row) && (mColumn == column);
|
||||
}
|
||||
|
@ -25,10 +25,10 @@ import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* A custom view to draw the day of the month in the today button in the options menu
|
||||
*/
|
||||
|
@ -80,8 +80,6 @@ import android.widget.ViewSwitcher;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
@ -90,6 +88,8 @@ import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* View for multi-day view. So far only 1 and 7 day have been tested.
|
||||
*/
|
||||
|
@ -16,11 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.calendar.event.EditEventHelper;
|
||||
import com.android.calendarcommon2.EventRecurrence;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
@ -38,9 +33,14 @@ import android.text.format.Time;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
|
||||
import com.android.calendar.event.EditEventHelper;
|
||||
import com.android.calendarcommon2.EventRecurrence;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* A helper class for deleting events. If a normal event is selected for
|
||||
* deletion, then this pops up a confirmation dialog. If the user confirms,
|
||||
@ -63,20 +63,6 @@ import java.util.Arrays;
|
||||
* {@link #delete()} multiple times).
|
||||
*/
|
||||
public class DeleteEventHelper {
|
||||
private final Activity mParent;
|
||||
private Context mContext;
|
||||
|
||||
private long mStartMillis;
|
||||
private long mEndMillis;
|
||||
private CalendarEventModel mModel;
|
||||
|
||||
/**
|
||||
* If true, then call finish() on the parent activity when done.
|
||||
*/
|
||||
private boolean mExitWhenDone;
|
||||
// the runnable to execute when the delete is confirmed
|
||||
private Runnable mCallback;
|
||||
|
||||
/**
|
||||
* These are the corresponding indices into the array of strings
|
||||
* "R.array.delete_repeating_labels" in the resource file.
|
||||
@ -84,7 +70,17 @@ public class DeleteEventHelper {
|
||||
public static final int DELETE_SELECTED = 0;
|
||||
public static final int DELETE_ALL_FOLLOWING = 1;
|
||||
public static final int DELETE_ALL = 2;
|
||||
|
||||
private final Activity mParent;
|
||||
private Context mContext;
|
||||
private long mStartMillis;
|
||||
private long mEndMillis;
|
||||
private CalendarEventModel mModel;
|
||||
/**
|
||||
* If true, then call finish() on the parent activity when done.
|
||||
*/
|
||||
private boolean mExitWhenDone;
|
||||
// the runnable to execute when the delete is confirmed
|
||||
private Runnable mCallback;
|
||||
private int mWhichDelete;
|
||||
private ArrayList<Integer> mWhichIndex;
|
||||
private AlertDialog mAlertDialog;
|
||||
@ -95,11 +91,67 @@ public class DeleteEventHelper {
|
||||
private AsyncQueryService mService;
|
||||
|
||||
private DeleteNotifyListener mDeleteStartedListener = null;
|
||||
/**
|
||||
* This callback is used when a normal event is deleted.
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteNormalDialogListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
deleteStarted();
|
||||
long id = mModel.mId; // mCursor.getInt(mEventIndexId);
|
||||
Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
|
||||
mService.startDelete(mService.getNextToken(), null, uri, null, null, Utils.UNDO_DELAY);
|
||||
if (mCallback != null) {
|
||||
mCallback.run();
|
||||
}
|
||||
if (mExitWhenDone) {
|
||||
mParent.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This callback is used when an exception to an event is deleted
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteExceptionDialogListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
deleteStarted();
|
||||
deleteExceptionEvent();
|
||||
if (mCallback != null) {
|
||||
mCallback.run();
|
||||
}
|
||||
if (mExitWhenDone) {
|
||||
mParent.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This callback is used when a list item for a repeating event is selected
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteListListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
// set mWhichDelete to the delete type at that index
|
||||
mWhichDelete = mWhichIndex.get(button);
|
||||
|
||||
public interface DeleteNotifyListener {
|
||||
public void onDeleteStarted();
|
||||
}
|
||||
|
||||
// Enable the "ok" button now that the user has selected which
|
||||
// events in the series to delete.
|
||||
Button ok = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
ok.setEnabled(true);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This callback is used when a repeating event is deleted.
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteRepeatingDialogListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
deleteStarted();
|
||||
if (mWhichDelete != -1) {
|
||||
deleteRepeatingEvent(mWhichDelete);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public DeleteEventHelper(Context context, Activity parentActivity, boolean exitWhenDone) {
|
||||
if (exitWhenDone && parentActivity == null) {
|
||||
@ -129,71 +181,6 @@ public class DeleteEventHelper {
|
||||
mExitWhenDone = exitWhenDone;
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback is used when a normal event is deleted.
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteNormalDialogListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
deleteStarted();
|
||||
long id = mModel.mId; // mCursor.getInt(mEventIndexId);
|
||||
Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
|
||||
mService.startDelete(mService.getNextToken(), null, uri, null, null, Utils.UNDO_DELAY);
|
||||
if (mCallback != null) {
|
||||
mCallback.run();
|
||||
}
|
||||
if (mExitWhenDone) {
|
||||
mParent.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This callback is used when an exception to an event is deleted
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteExceptionDialogListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
deleteStarted();
|
||||
deleteExceptionEvent();
|
||||
if (mCallback != null) {
|
||||
mCallback.run();
|
||||
}
|
||||
if (mExitWhenDone) {
|
||||
mParent.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This callback is used when a list item for a repeating event is selected
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteListListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
// set mWhichDelete to the delete type at that index
|
||||
mWhichDelete = mWhichIndex.get(button);
|
||||
|
||||
// Enable the "ok" button now that the user has selected which
|
||||
// events in the series to delete.
|
||||
Button ok = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
ok.setEnabled(true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This callback is used when a repeating event is deleted.
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDeleteRepeatingDialogListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
deleteStarted();
|
||||
if (mWhichDelete != -1) {
|
||||
deleteRepeatingEvent(mWhichDelete);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Does the required processing for deleting an event, which includes
|
||||
* first popping up a dialog asking for confirmation (if the event is
|
||||
@ -465,4 +452,8 @@ public class DeleteEventHelper {
|
||||
mAlertDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public interface DeleteNotifyListener {
|
||||
public void onDeleteStarted();
|
||||
}
|
||||
}
|
||||
|
@ -16,14 +16,14 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.widget.Button;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* A helper class for editing the response to an invitation when the invitation
|
||||
* is a repeating event.
|
||||
@ -39,6 +39,21 @@ public class EditResponseHelper implements DialogInterface.OnClickListener, OnDi
|
||||
* and is invoked when the "Ok" button is selected.
|
||||
*/
|
||||
private DialogInterface.OnClickListener mDialogListener;
|
||||
/**
|
||||
* This callback is used when a list item is selected
|
||||
*/
|
||||
private DialogInterface.OnClickListener mListListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
mWhichEvents = which;
|
||||
|
||||
// Enable the "ok" button now that the user has selected which
|
||||
// events in the series to delete.
|
||||
Button ok = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
ok.setEnabled(true);
|
||||
}
|
||||
};
|
||||
private DialogInterface.OnDismissListener mDismissListener;
|
||||
|
||||
public EditResponseHelper(Activity parent) {
|
||||
mParent = parent;
|
||||
@ -93,24 +108,6 @@ public class EditResponseHelper implements DialogInterface.OnClickListener, OnDi
|
||||
mClickedOk = clickedOk;
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback is used when a list item is selected
|
||||
*/
|
||||
private DialogInterface.OnClickListener mListListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
mWhichEvents = which;
|
||||
|
||||
// Enable the "ok" button now that the user has selected which
|
||||
// events in the series to delete.
|
||||
Button ok = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
ok.setEnabled(true);
|
||||
}
|
||||
};
|
||||
|
||||
private DialogInterface.OnDismissListener mDismissListener;
|
||||
|
||||
|
||||
/**
|
||||
* Set the dismiss listener to be called when the dialog is ended. There,
|
||||
* use getWhichEvents() to see how the dialog was dismissed; if it returns
|
||||
|
@ -16,11 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.common.contacts.BaseEmailAddressAdapter;
|
||||
import com.android.ex.chips.AccountSpecifier;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
@ -28,6 +23,11 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.common.contacts.BaseEmailAddressAdapter;
|
||||
import com.android.ex.chips.AccountSpecifier;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* An adaptation of {@link BaseEmailAddressAdapter} for the Email app. The main
|
||||
* purpose of the class is to bind the generic implementation to the resources
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
@ -39,6 +37,8 @@ import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
// TODO: should Event be Parcelable so it can be passed via Intents?
|
||||
public class Event implements Cloneable {
|
||||
|
||||
@ -60,10 +60,6 @@ public class Event implements Cloneable {
|
||||
private static final String SORT_ALLDAY_BY =
|
||||
"startDay ASC, endDay DESC, title ASC";
|
||||
private static final String DISPLAY_AS_ALLDAY = "dispAllday";
|
||||
|
||||
private static final String EVENTS_WHERE = DISPLAY_AS_ALLDAY + "=0";
|
||||
private static final String ALLDAY_WHERE = DISPLAY_AS_ALLDAY + "=1";
|
||||
|
||||
// The projection to use when querying instances to build a list of events
|
||||
public static final String[] EVENT_PROJECTION = new String[] {
|
||||
Instances.TITLE, // 0
|
||||
@ -88,7 +84,8 @@ public class Event implements Cloneable {
|
||||
Instances.ALL_DAY + "=1 OR (" + Instances.END + "-" + Instances.BEGIN + ")>="
|
||||
+ DateUtils.DAY_IN_MILLIS + " AS " + DISPLAY_AS_ALLDAY, // 19
|
||||
};
|
||||
|
||||
private static final String EVENTS_WHERE = DISPLAY_AS_ALLDAY + "=0";
|
||||
private static final String ALLDAY_WHERE = DISPLAY_AS_ALLDAY + "=1";
|
||||
// The indices for the projection array above.
|
||||
private static final int PROJECTION_TITLE_INDEX = 0;
|
||||
private static final int PROJECTION_LOCATION_INDEX = 1;
|
||||
@ -109,6 +106,8 @@ public class Event implements Cloneable {
|
||||
private static final int PROJECTION_ORGANIZER_INDEX = 17;
|
||||
private static final int PROJECTION_GUESTS_CAN_INVITE_OTHERS_INDEX = 18;
|
||||
private static final int PROJECTION_DISPLAY_AS_ALLDAY = 19;
|
||||
private static String mNoTitleString;
|
||||
private static int mNoColorColor;
|
||||
|
||||
static {
|
||||
if (!Utils.isJellybeanOrLater()) {
|
||||
@ -116,9 +115,6 @@ public class Event implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
private static String mNoTitleString;
|
||||
private static int mNoColorColor;
|
||||
|
||||
public long id;
|
||||
public int color;
|
||||
public CharSequence title;
|
||||
@ -134,69 +130,22 @@ public class Event implements Cloneable {
|
||||
|
||||
public long startMillis; // UTC milliseconds since the epoch
|
||||
public long endMillis; // UTC milliseconds since the epoch
|
||||
private int mColumn;
|
||||
private int mMaxColumns;
|
||||
|
||||
public boolean hasAlarm;
|
||||
public boolean isRepeating;
|
||||
|
||||
public int selfAttendeeStatus;
|
||||
|
||||
// The coordinates of the event rectangle drawn on the screen.
|
||||
public float left;
|
||||
public float right;
|
||||
public float top;
|
||||
public float bottom;
|
||||
|
||||
// These 4 fields are used for navigating among events within the selected
|
||||
// hour in the Day and Week view.
|
||||
public Event nextRight;
|
||||
public Event nextLeft;
|
||||
public Event nextUp;
|
||||
public Event nextDown;
|
||||
|
||||
@Override
|
||||
public final Object clone() throws CloneNotSupportedException {
|
||||
super.clone();
|
||||
Event e = new Event();
|
||||
|
||||
e.title = title;
|
||||
e.color = color;
|
||||
e.location = location;
|
||||
e.allDay = allDay;
|
||||
e.startDay = startDay;
|
||||
e.endDay = endDay;
|
||||
e.startTime = startTime;
|
||||
e.endTime = endTime;
|
||||
e.startMillis = startMillis;
|
||||
e.endMillis = endMillis;
|
||||
e.hasAlarm = hasAlarm;
|
||||
e.isRepeating = isRepeating;
|
||||
e.selfAttendeeStatus = selfAttendeeStatus;
|
||||
e.organizer = organizer;
|
||||
e.guestsCanModify = guestsCanModify;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
public final void copyTo(Event dest) {
|
||||
dest.id = id;
|
||||
dest.title = title;
|
||||
dest.color = color;
|
||||
dest.location = location;
|
||||
dest.allDay = allDay;
|
||||
dest.startDay = startDay;
|
||||
dest.endDay = endDay;
|
||||
dest.startTime = startTime;
|
||||
dest.endTime = endTime;
|
||||
dest.startMillis = startMillis;
|
||||
dest.endMillis = endMillis;
|
||||
dest.hasAlarm = hasAlarm;
|
||||
dest.isRepeating = isRepeating;
|
||||
dest.selfAttendeeStatus = selfAttendeeStatus;
|
||||
dest.organizer = organizer;
|
||||
dest.guestsCanModify = guestsCanModify;
|
||||
}
|
||||
private int mColumn;
|
||||
private int mMaxColumns;
|
||||
|
||||
public static final Event newInstance() {
|
||||
Event e = new Event();
|
||||
@ -538,6 +487,49 @@ public class Event implements Cloneable {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object clone() throws CloneNotSupportedException {
|
||||
super.clone();
|
||||
Event e = new Event();
|
||||
|
||||
e.title = title;
|
||||
e.color = color;
|
||||
e.location = location;
|
||||
e.allDay = allDay;
|
||||
e.startDay = startDay;
|
||||
e.endDay = endDay;
|
||||
e.startTime = startTime;
|
||||
e.endTime = endTime;
|
||||
e.startMillis = startMillis;
|
||||
e.endMillis = endMillis;
|
||||
e.hasAlarm = hasAlarm;
|
||||
e.isRepeating = isRepeating;
|
||||
e.selfAttendeeStatus = selfAttendeeStatus;
|
||||
e.organizer = organizer;
|
||||
e.guestsCanModify = guestsCanModify;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
public final void copyTo(Event dest) {
|
||||
dest.id = id;
|
||||
dest.title = title;
|
||||
dest.color = color;
|
||||
dest.location = location;
|
||||
dest.allDay = allDay;
|
||||
dest.startDay = startDay;
|
||||
dest.endDay = endDay;
|
||||
dest.startTime = startTime;
|
||||
dest.endTime = endTime;
|
||||
dest.startMillis = startMillis;
|
||||
dest.endMillis = endMillis;
|
||||
dest.hasAlarm = hasAlarm;
|
||||
dest.isRepeating = isRepeating;
|
||||
dest.selfAttendeeStatus = selfAttendeeStatus;
|
||||
dest.organizer = organizer;
|
||||
dest.guestsCanModify = guestsCanModify;
|
||||
}
|
||||
|
||||
public final void dump() {
|
||||
Log.e("Cal", "+-----------------------------------------+");
|
||||
Log.e("Cal", "+ id = " + id);
|
||||
@ -605,38 +597,38 @@ public class Event implements Cloneable {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setColumn(int column) {
|
||||
mColumn = column;
|
||||
}
|
||||
|
||||
public int getColumn() {
|
||||
return mColumn;
|
||||
}
|
||||
|
||||
public void setMaxColumns(int maxColumns) {
|
||||
mMaxColumns = maxColumns;
|
||||
public void setColumn(int column) {
|
||||
mColumn = column;
|
||||
}
|
||||
|
||||
public int getMaxColumns() {
|
||||
return mMaxColumns;
|
||||
}
|
||||
|
||||
public void setStartMillis(long startMillis) {
|
||||
this.startMillis = startMillis;
|
||||
public void setMaxColumns(int maxColumns) {
|
||||
mMaxColumns = maxColumns;
|
||||
}
|
||||
|
||||
public long getStartMillis() {
|
||||
return startMillis;
|
||||
}
|
||||
|
||||
public void setEndMillis(long endMillis) {
|
||||
this.endMillis = endMillis;
|
||||
public void setStartMillis(long startMillis) {
|
||||
this.startMillis = startMillis;
|
||||
}
|
||||
|
||||
public long getEndMillis() {
|
||||
return endMillis;
|
||||
}
|
||||
|
||||
public void setEndMillis(long endMillis) {
|
||||
this.endMillis = endMillis;
|
||||
}
|
||||
|
||||
public boolean drawAsAllday() {
|
||||
// Use >= so we'll pick up Exchange allday events
|
||||
return allDay || endMillis - startMillis >= DateUtils.DAY_IN_MILLIS;
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
public class EventGeometry {
|
||||
|
@ -32,11 +32,11 @@ import android.widget.Toast;
|
||||
|
||||
import com.android.calendar.CalendarEventModel.ReminderEntry;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
@ -16,13 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
import static com.android.calendar.CalendarController.EVENT_EDIT_ON_LAUNCH;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
@ -116,6 +109,13 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
import static com.android.calendar.CalendarController.EVENT_EDIT_ON_LAUNCH;
|
||||
|
||||
public class EventInfoFragment extends DialogFragment implements OnCheckedChangeListener,
|
||||
CalendarController.EventHandler, OnClickListener, DeleteEventHelper.DeleteNotifyListener,
|
||||
OnColorSelectedListener {
|
||||
@ -124,9 +124,11 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
|
||||
public static final String TAG = "EventInfoFragment";
|
||||
public static final String COLOR_PICKER_DIALOG_TAG = "EventColorPickerDialog";
|
||||
|
||||
private static final int REQUEST_CODE_COLOR_PICKER = 0;
|
||||
|
||||
// Style of view
|
||||
public static final int FULL_WINDOW_STYLE = 0;
|
||||
public static final int DIALOG_WINDOW_STYLE = 1;
|
||||
public static final int COLORS_INDEX_COLOR = 1;
|
||||
public static final int COLORS_INDEX_COLOR_KEY = 2;
|
||||
protected static final String BUNDLE_KEY_EVENT_ID = "key_event_id";
|
||||
protected static final String BUNDLE_KEY_START_MILLIS = "key_start_millis";
|
||||
protected static final String BUNDLE_KEY_END_MILLIS = "key_end_millis";
|
||||
@ -148,25 +150,38 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
protected static final String BUNDLE_KEY_RESPONSE_WHICH_EVENTS = "key_response_which_events";
|
||||
protected static final String BUNDLE_KEY_REMINDER_MINUTES = "key_reminder_minutes";
|
||||
protected static final String BUNDLE_KEY_REMINDER_METHODS = "key_reminder_methods";
|
||||
|
||||
|
||||
private static final String PERIOD_SPACE = ". ";
|
||||
|
||||
private static final String NO_EVENT_COLOR = "";
|
||||
|
||||
/**
|
||||
* These are the corresponding indices into the array of strings
|
||||
* "R.array.change_response_labels" in the resource file.
|
||||
*/
|
||||
static final int UPDATE_SINGLE = 0;
|
||||
static final int UPDATE_ALL = 1;
|
||||
|
||||
// Style of view
|
||||
public static final int FULL_WINDOW_STYLE = 0;
|
||||
public static final int DIALOG_WINDOW_STYLE = 1;
|
||||
|
||||
private int mWindowStyle = DIALOG_WINDOW_STYLE;
|
||||
|
||||
static final String[] CALENDARS_PROJECTION = new String[]{
|
||||
Calendars._ID, // 0
|
||||
Calendars.CALENDAR_DISPLAY_NAME, // 1
|
||||
Calendars.OWNER_ACCOUNT, // 2
|
||||
Calendars.CAN_ORGANIZER_RESPOND, // 3
|
||||
Calendars.ACCOUNT_NAME, // 4
|
||||
Calendars.ACCOUNT_TYPE // 5
|
||||
};
|
||||
static final int CALENDARS_INDEX_DISPLAY_NAME = 1;
|
||||
static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
|
||||
static final int CALENDARS_INDEX_OWNER_CAN_RESPOND = 3;
|
||||
static final int CALENDARS_INDEX_ACCOUNT_NAME = 4;
|
||||
static final int CALENDARS_INDEX_ACCOUNT_TYPE = 5;
|
||||
static final String CALENDARS_WHERE = Calendars._ID + "=?";
|
||||
static final String CALENDARS_DUPLICATE_NAME_WHERE = Calendars.CALENDAR_DISPLAY_NAME + "=?";
|
||||
static final String CALENDARS_VISIBLE_WHERE = Calendars.VISIBLE + "=?";
|
||||
static final String[] COLORS_PROJECTION = new String[]{
|
||||
Colors._ID, // 0
|
||||
Colors.COLOR, // 1
|
||||
Colors.COLOR_KEY // 2
|
||||
};
|
||||
static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE +
|
||||
"=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_EVENT;
|
||||
private static final int REQUEST_CODE_COLOR_PICKER = 0;
|
||||
private static final String PERIOD_SPACE = ". ";
|
||||
private static final String NO_EVENT_COLOR = "";
|
||||
// Query tokens for QueryHandler
|
||||
private static final int TOKEN_QUERY_EVENT = 1 << 0;
|
||||
private static final int TOKEN_QUERY_CALENDARS = 1 << 1;
|
||||
@ -175,13 +190,9 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
private static final int TOKEN_QUERY_REMINDERS = 1 << 4;
|
||||
private static final int TOKEN_QUERY_VISIBLE_CALENDARS = 1 << 5;
|
||||
private static final int TOKEN_QUERY_COLORS = 1 << 6;
|
||||
|
||||
private static final int TOKEN_QUERY_ALL = TOKEN_QUERY_DUPLICATE_CALENDARS
|
||||
| TOKEN_QUERY_ATTENDEES | TOKEN_QUERY_CALENDARS | TOKEN_QUERY_EVENT
|
||||
| TOKEN_QUERY_REMINDERS | TOKEN_QUERY_VISIBLE_CALENDARS | TOKEN_QUERY_COLORS;
|
||||
|
||||
private int mCurrentQuery = 0;
|
||||
|
||||
private static final String[] EVENT_PROJECTION = new String[] {
|
||||
Events._ID, // 0 do not remove; used in DeleteEventHelper
|
||||
Events.TITLE, // 1 do not remove; used in DeleteEventHelper
|
||||
@ -229,7 +240,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
private static final int EVENT_INDEX_CUSTOM_APP_URI = 19;
|
||||
private static final int EVENT_INDEX_DTEND = 20;
|
||||
private static final int EVENT_INDEX_DURATION = 21;
|
||||
|
||||
private static final String[] ATTENDEES_PROJECTION = new String[] {
|
||||
Attendees._ID, // 0
|
||||
Attendees.ATTENDEE_NAME, // 1
|
||||
@ -246,6 +256,26 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
private static final int ATTENDEES_INDEX_STATUS = 4;
|
||||
private static final int ATTENDEES_INDEX_IDENTITY = 5;
|
||||
private static final int ATTENDEES_INDEX_ID_NAMESPACE = 6;
|
||||
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
|
||||
private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
|
||||
+ Attendees.ATTENDEE_EMAIL + " ASC";
|
||||
private static final String[] REMINDERS_PROJECTION = new String[] {
|
||||
Reminders._ID, // 0
|
||||
Reminders.MINUTES, // 1
|
||||
Reminders.METHOD // 2
|
||||
};
|
||||
private static final int REMINDERS_INDEX_ID = 0;
|
||||
private static final int REMINDERS_MINUTES_ID = 1;
|
||||
private static final int REMINDERS_METHOD_ID = 2;
|
||||
private static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=?";
|
||||
private static final int FADE_IN_TIME = 300; // in milliseconds
|
||||
private static final int LOADING_MSG_DELAY = 600; // in milliseconds
|
||||
private static final int LOADING_MSG_MIN_DISPLAY_TIME = 600;
|
||||
private static float mScale = 0; // Used for supporting different screen densities
|
||||
private static int mCustomAppIconSize = 32;
|
||||
private static int mDialogWidth = 500;
|
||||
private static int mDialogHeight = 600;
|
||||
private static int DIALOG_TOP_MARGIN = 8;
|
||||
|
||||
static {
|
||||
if (!Utils.isJellybeanOrLater()) {
|
||||
@ -257,69 +287,28 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
}
|
||||
}
|
||||
|
||||
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
|
||||
|
||||
private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
|
||||
+ Attendees.ATTENDEE_EMAIL + " ASC";
|
||||
|
||||
private static final String[] REMINDERS_PROJECTION = new String[] {
|
||||
Reminders._ID, // 0
|
||||
Reminders.MINUTES, // 1
|
||||
Reminders.METHOD // 2
|
||||
};
|
||||
private static final int REMINDERS_INDEX_ID = 0;
|
||||
private static final int REMINDERS_MINUTES_ID = 1;
|
||||
private static final int REMINDERS_METHOD_ID = 2;
|
||||
|
||||
private static final String REMINDERS_WHERE = Reminders.EVENT_ID + "=?";
|
||||
|
||||
static final String[] CALENDARS_PROJECTION = new String[] {
|
||||
Calendars._ID, // 0
|
||||
Calendars.CALENDAR_DISPLAY_NAME, // 1
|
||||
Calendars.OWNER_ACCOUNT, // 2
|
||||
Calendars.CAN_ORGANIZER_RESPOND, // 3
|
||||
Calendars.ACCOUNT_NAME, // 4
|
||||
Calendars.ACCOUNT_TYPE // 5
|
||||
};
|
||||
static final int CALENDARS_INDEX_DISPLAY_NAME = 1;
|
||||
static final int CALENDARS_INDEX_OWNER_ACCOUNT = 2;
|
||||
static final int CALENDARS_INDEX_OWNER_CAN_RESPOND = 3;
|
||||
static final int CALENDARS_INDEX_ACCOUNT_NAME = 4;
|
||||
static final int CALENDARS_INDEX_ACCOUNT_TYPE = 5;
|
||||
|
||||
static final String CALENDARS_WHERE = Calendars._ID + "=?";
|
||||
static final String CALENDARS_DUPLICATE_NAME_WHERE = Calendars.CALENDAR_DISPLAY_NAME + "=?";
|
||||
static final String CALENDARS_VISIBLE_WHERE = Calendars.VISIBLE + "=?";
|
||||
|
||||
static final String[] COLORS_PROJECTION = new String[] {
|
||||
Colors._ID, // 0
|
||||
Colors.COLOR, // 1
|
||||
Colors.COLOR_KEY // 2
|
||||
};
|
||||
|
||||
static final String COLORS_WHERE = Colors.ACCOUNT_NAME + "=? AND " + Colors.ACCOUNT_TYPE +
|
||||
"=? AND " + Colors.COLOR_TYPE + "=" + Colors.TYPE_EVENT;
|
||||
|
||||
public static final int COLORS_INDEX_COLOR = 1;
|
||||
public static final int COLORS_INDEX_COLOR_KEY = 2;
|
||||
|
||||
private final ArrayList<LinearLayout> mReminderViews = new ArrayList<LinearLayout>(0);
|
||||
public ArrayList<ReminderEntry> mReminders;
|
||||
public ArrayList<ReminderEntry> mOriginalReminders = new ArrayList<ReminderEntry>();
|
||||
public ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>();
|
||||
ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<Attendee> mNoResponseAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<String> mToEmails = new ArrayList<String>();
|
||||
ArrayList<String> mCcEmails = new ArrayList<String>();
|
||||
private int mWindowStyle = DIALOG_WINDOW_STYLE;
|
||||
private int mCurrentQuery = 0;
|
||||
private View mView;
|
||||
|
||||
private Uri mUri;
|
||||
private long mEventId;
|
||||
private Cursor mEventCursor;
|
||||
private Cursor mAttendeesCursor;
|
||||
private Cursor mCalendarsCursor;
|
||||
private Cursor mRemindersCursor;
|
||||
|
||||
private static float mScale = 0; // Used for supporting different screen densities
|
||||
|
||||
private static int mCustomAppIconSize = 32;
|
||||
|
||||
private long mStartMillis;
|
||||
private long mEndMillis;
|
||||
private boolean mAllDay;
|
||||
|
||||
private boolean mHasAttendeeData;
|
||||
private String mEventOrganizerEmail;
|
||||
private String mEventOrganizerDisplayName = "";
|
||||
@ -335,7 +324,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
private EditResponseHelper mEditResponseHelper;
|
||||
private boolean mDeleteDialogVisible = false;
|
||||
private DeleteEventHelper mDeleteHelper;
|
||||
|
||||
private int mOriginalAttendeeResponse;
|
||||
private int mAttendeeResponseFromIntent = Attendees.ATTENDEE_STATUS_NONE;
|
||||
private int mUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
|
||||
@ -349,7 +337,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
private String mCalendarAllowedReminders;
|
||||
// Used to prevent saving changes in event if it is being deleted.
|
||||
private boolean mEventDeletionStarted = false;
|
||||
|
||||
private TextView mTitle;
|
||||
private TextView mWhenDateTime;
|
||||
private TextView mWhere;
|
||||
@ -362,63 +349,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
private View mLoadingMsgView;
|
||||
private ObjectAnimator mAnimateAlpha;
|
||||
private long mLoadingMsgStartTime;
|
||||
|
||||
private EventColorPickerDialog mColorPickerDialog;
|
||||
private SparseIntArray mDisplayColorKeyMap = new SparseIntArray();
|
||||
private int[] mColors;
|
||||
private int mOriginalColor = -1;
|
||||
private boolean mOriginalColorInitialized = false;
|
||||
private int mCalendarColor = -1;
|
||||
private boolean mCalendarColorInitialized = false;
|
||||
private int mCurrentColor = -1;
|
||||
private boolean mCurrentColorInitialized = false;
|
||||
private int mCurrentColorKey = -1;
|
||||
|
||||
private static final int FADE_IN_TIME = 300; // in milliseconds
|
||||
private static final int LOADING_MSG_DELAY = 600; // in milliseconds
|
||||
private static final int LOADING_MSG_MIN_DISPLAY_TIME = 600;
|
||||
private boolean mNoCrossFade = false; // Used to prevent repeated cross-fade
|
||||
private RadioGroup mResponseRadioGroup;
|
||||
|
||||
ArrayList<Attendee> mAcceptedAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<Attendee> mDeclinedAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<Attendee> mTentativeAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<Attendee> mNoResponseAttendees = new ArrayList<Attendee>();
|
||||
ArrayList<String> mToEmails = new ArrayList<String>();
|
||||
ArrayList<String> mCcEmails = new ArrayList<String>();
|
||||
|
||||
private int mDefaultReminderMinutes;
|
||||
private final ArrayList<LinearLayout> mReminderViews = new ArrayList<LinearLayout>(0);
|
||||
public ArrayList<ReminderEntry> mReminders;
|
||||
public ArrayList<ReminderEntry> mOriginalReminders = new ArrayList<ReminderEntry>();
|
||||
public ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>();
|
||||
private boolean mUserModifiedReminders = false;
|
||||
|
||||
/**
|
||||
* Contents of the "minutes" spinner. This has default values from the XML file, augmented
|
||||
* with any additional values that were already associated with the event.
|
||||
*/
|
||||
private ArrayList<Integer> mReminderMinuteValues;
|
||||
private ArrayList<String> mReminderMinuteLabels;
|
||||
|
||||
/**
|
||||
* Contents of the "methods" spinner. The "values" list specifies the method constant
|
||||
* (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that
|
||||
* aren't allowed by the Calendar will be removed.
|
||||
*/
|
||||
private ArrayList<Integer> mReminderMethodValues;
|
||||
private ArrayList<String> mReminderMethodLabels;
|
||||
|
||||
private QueryHandler mHandler;
|
||||
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateEvent(mView);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mLoadingMsgAlphaUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -430,218 +360,63 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private EventColorPickerDialog mColorPickerDialog;
|
||||
private SparseIntArray mDisplayColorKeyMap = new SparseIntArray();
|
||||
private int[] mColors;
|
||||
private int mOriginalColor = -1;
|
||||
private boolean mOriginalColorInitialized = false;
|
||||
private int mCalendarColor = -1;
|
||||
private boolean mCalendarColorInitialized = false;
|
||||
private int mCurrentColor = -1;
|
||||
private boolean mCurrentColorInitialized = false;
|
||||
private int mCurrentColorKey = -1;
|
||||
private boolean mNoCrossFade = false; // Used to prevent repeated cross-fade
|
||||
private RadioGroup mResponseRadioGroup;
|
||||
private int mDefaultReminderMinutes;
|
||||
private boolean mUserModifiedReminders = false;
|
||||
/**
|
||||
* Contents of the "minutes" spinner. This has default values from the XML file, augmented
|
||||
* with any additional values that were already associated with the event.
|
||||
*/
|
||||
private ArrayList<Integer> mReminderMinuteValues;
|
||||
private ArrayList<String> mReminderMinuteLabels;
|
||||
/**
|
||||
* Contents of the "methods" spinner. The "values" list specifies the method constant
|
||||
* (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that
|
||||
* aren't allowed by the Calendar will be removed.
|
||||
*/
|
||||
private ArrayList<Integer> mReminderMethodValues;
|
||||
private ArrayList<String> mReminderMethodLabels;
|
||||
private QueryHandler mHandler;
|
||||
private OnItemSelectedListener mReminderChangeListener;
|
||||
|
||||
private static int mDialogWidth = 500;
|
||||
private static int mDialogHeight = 600;
|
||||
private static int DIALOG_TOP_MARGIN = 8;
|
||||
private boolean mIsDialog = false;
|
||||
private boolean mIsPaused = true;
|
||||
private boolean mDismissOnResume = false;
|
||||
private final Runnable onDeleteRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (EventInfoFragment.this.mIsPaused) {
|
||||
mDismissOnResume = true;
|
||||
return;
|
||||
}
|
||||
if (EventInfoFragment.this.isVisible()) {
|
||||
EventInfoFragment.this.dismiss();
|
||||
}
|
||||
}
|
||||
};
|
||||
private int mX = -1;
|
||||
private int mY = -1;
|
||||
private int mMinTop; // Dialog cannot be above this location
|
||||
private boolean mIsTabletConfig;
|
||||
private Activity mActivity;
|
||||
private Context mContext;
|
||||
|
||||
private CalendarController mController;
|
||||
|
||||
private class QueryHandler extends AsyncQueryService {
|
||||
public QueryHandler(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
// if the activity is finishing, then close the cursor and return
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null || activity.isFinishing()) {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (token) {
|
||||
case TOKEN_QUERY_EVENT:
|
||||
mEventCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
if (initEventCursor()) {
|
||||
// The cursor is empty. This can happen if the event was
|
||||
// deleted.
|
||||
// FRAG_TODO we should no longer rely on Activity.finish()
|
||||
activity.finish();
|
||||
return;
|
||||
}
|
||||
if (!mCalendarColorInitialized) {
|
||||
mCalendarColor = Utils.getDisplayColorFromColor(
|
||||
mEventCursor.getInt(EVENT_INDEX_CALENDAR_COLOR));
|
||||
mCalendarColorInitialized = true;
|
||||
}
|
||||
|
||||
if (!mOriginalColorInitialized) {
|
||||
mOriginalColor = mEventCursor.isNull(EVENT_INDEX_EVENT_COLOR)
|
||||
? mCalendarColor : Utils.getDisplayColorFromColor(
|
||||
mEventCursor.getInt(EVENT_INDEX_EVENT_COLOR));
|
||||
mOriginalColorInitialized = true;
|
||||
}
|
||||
|
||||
if (!mCurrentColorInitialized) {
|
||||
mCurrentColor = mOriginalColor;
|
||||
mCurrentColorInitialized = true;
|
||||
}
|
||||
|
||||
updateEvent(mView);
|
||||
prepareReminders();
|
||||
|
||||
// start calendar query
|
||||
Uri uri = Calendars.CONTENT_URI;
|
||||
String[] args = new String[] {
|
||||
Long.toString(mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID))};
|
||||
startQuery(TOKEN_QUERY_CALENDARS, null, uri, CALENDARS_PROJECTION,
|
||||
CALENDARS_WHERE, args, null);
|
||||
break;
|
||||
case TOKEN_QUERY_CALENDARS:
|
||||
mCalendarsCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
updateCalendar(mView);
|
||||
// FRAG_TODO fragments shouldn't set the title anymore
|
||||
updateTitle();
|
||||
|
||||
args = new String[] {
|
||||
mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
|
||||
mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE) };
|
||||
uri = Colors.CONTENT_URI;
|
||||
startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE, args,
|
||||
null);
|
||||
|
||||
if (!mIsBusyFreeCalendar) {
|
||||
args = new String[] { Long.toString(mEventId) };
|
||||
|
||||
// start attendees query
|
||||
uri = Attendees.CONTENT_URI;
|
||||
startQuery(TOKEN_QUERY_ATTENDEES, null, uri, ATTENDEES_PROJECTION,
|
||||
ATTENDEES_WHERE, args, ATTENDEES_SORT_ORDER);
|
||||
} else {
|
||||
sendAccessibilityEventIfQueryDone(TOKEN_QUERY_ATTENDEES);
|
||||
}
|
||||
if (mHasAlarm) {
|
||||
// start reminders query
|
||||
args = new String[] { Long.toString(mEventId) };
|
||||
uri = Reminders.CONTENT_URI;
|
||||
startQuery(TOKEN_QUERY_REMINDERS, null, uri,
|
||||
REMINDERS_PROJECTION, REMINDERS_WHERE, args, null);
|
||||
} else {
|
||||
sendAccessibilityEventIfQueryDone(TOKEN_QUERY_REMINDERS);
|
||||
}
|
||||
break;
|
||||
case TOKEN_QUERY_COLORS:
|
||||
ArrayList<Integer> colors = new ArrayList<Integer>();
|
||||
if (cursor.moveToFirst()) {
|
||||
do
|
||||
{
|
||||
int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
|
||||
int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
|
||||
int displayColor = Utils.getDisplayColorFromColor(rawColor);
|
||||
mDisplayColorKeyMap.put(displayColor, colorKey);
|
||||
colors.add(displayColor);
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
Integer[] sortedColors = new Integer[colors.size()];
|
||||
Arrays.sort(colors.toArray(sortedColors), new HsvColorComparator());
|
||||
mColors = new int[sortedColors.length];
|
||||
for (int i = 0; i < sortedColors.length; i++) {
|
||||
mColors[i] = sortedColors[i].intValue();
|
||||
|
||||
float[] hsv = new float[3];
|
||||
Color.colorToHSV(mColors[i], hsv);
|
||||
if (DEBUG) {
|
||||
Log.d("Color", "H:" + hsv[0] + ",S:" + hsv[1] + ",V:" + hsv[2]);
|
||||
}
|
||||
}
|
||||
if (mCanModifyCalendar) {
|
||||
View button = mView.findViewById(R.id.change_color);
|
||||
if (button != null && mColors.length > 0) {
|
||||
button.setEnabled(true);
|
||||
button.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
updateMenu();
|
||||
break;
|
||||
case TOKEN_QUERY_ATTENDEES:
|
||||
mAttendeesCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
initAttendeesCursor(mView);
|
||||
updateResponse(mView);
|
||||
break;
|
||||
case TOKEN_QUERY_REMINDERS:
|
||||
mRemindersCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
initReminders(mView, mRemindersCursor);
|
||||
break;
|
||||
case TOKEN_QUERY_VISIBLE_CALENDARS:
|
||||
if (cursor.getCount() > 1) {
|
||||
// Start duplicate calendars query to detect whether to add the calendar
|
||||
// email to the calendar owner display.
|
||||
String displayName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
|
||||
mHandler.startQuery(TOKEN_QUERY_DUPLICATE_CALENDARS, null,
|
||||
Calendars.CONTENT_URI, CALENDARS_PROJECTION,
|
||||
CALENDARS_DUPLICATE_NAME_WHERE, new String[] {displayName}, null);
|
||||
} else {
|
||||
// Don't need to display the calendar owner when there is only a single
|
||||
// calendar. Skip the duplicate calendars query.
|
||||
setVisibilityCommon(mView, R.id.calendar_container, View.GONE);
|
||||
mCurrentQuery |= TOKEN_QUERY_DUPLICATE_CALENDARS;
|
||||
}
|
||||
break;
|
||||
case TOKEN_QUERY_DUPLICATE_CALENDARS:
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
|
||||
// Calendar display name
|
||||
String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
|
||||
sb.append(calendarName);
|
||||
|
||||
// Show email account if display name is not unique and
|
||||
// display name != email
|
||||
String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
|
||||
if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email) &&
|
||||
Utils.isValidEmail(email)) {
|
||||
sb.append(" (").append(email).append(")");
|
||||
}
|
||||
|
||||
setVisibilityCommon(mView, R.id.calendar_container, View.VISIBLE);
|
||||
setTextCommon(mView, R.id.calendar_name, sb);
|
||||
break;
|
||||
}
|
||||
cursor.close();
|
||||
sendAccessibilityEventIfQueryDone(token);
|
||||
|
||||
// All queries are done, show the view.
|
||||
if (mCurrentQuery == TOKEN_QUERY_ALL) {
|
||||
if (mLoadingMsgView.getAlpha() == 1) {
|
||||
// Loading message is showing, let it stay a bit more (to prevent
|
||||
// flashing) by adding a start delay to the event animation
|
||||
long timeDiff = LOADING_MSG_MIN_DISPLAY_TIME - (System.currentTimeMillis() -
|
||||
mLoadingMsgStartTime);
|
||||
if (timeDiff > 0) {
|
||||
mAnimateAlpha.setStartDelay(timeDiff);
|
||||
}
|
||||
}
|
||||
if (!mAnimateAlpha.isRunning() &&!mAnimateAlpha.isStarted() && !mNoCrossFade) {
|
||||
mAnimateAlpha.start();
|
||||
} else {
|
||||
mScrollView.setAlpha(1);
|
||||
mLoadingMsgView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
public void run() {
|
||||
updateEvent(mView);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAccessibilityEventIfQueryDone(int token) {
|
||||
mCurrentQuery |= token;
|
||||
if (mCurrentQuery == TOKEN_QUERY_ALL) {
|
||||
sendAccessibilityEvent();
|
||||
}
|
||||
}
|
||||
};
|
||||
private CalendarController mController;
|
||||
|
||||
public EventInfoFragment(Context context, Uri uri, long startMillis, long endMillis,
|
||||
int attendeeResponse, boolean isDialog, int windowStyle,
|
||||
@ -687,6 +462,69 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
mEventId = eventId;
|
||||
}
|
||||
|
||||
public static int getResponseFromButtonId(int buttonId) {
|
||||
int response;
|
||||
if (buttonId == R.id.response_yes) {
|
||||
response = Attendees.ATTENDEE_STATUS_ACCEPTED;
|
||||
} else if (buttonId == R.id.response_maybe) {
|
||||
response = Attendees.ATTENDEE_STATUS_TENTATIVE;
|
||||
} else if (buttonId == R.id.response_no) {
|
||||
response = Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
} else {
|
||||
response = Attendees.ATTENDEE_STATUS_NONE;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public static int findButtonIdForResponse(int response) {
|
||||
int buttonId;
|
||||
switch (response) {
|
||||
case Attendees.ATTENDEE_STATUS_ACCEPTED:
|
||||
buttonId = R.id.response_yes;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_TENTATIVE:
|
||||
buttonId = R.id.response_maybe;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_DECLINED:
|
||||
buttonId = R.id.response_no;
|
||||
break;
|
||||
default:
|
||||
buttonId = -1;
|
||||
}
|
||||
return buttonId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an integer array asset into a list.
|
||||
*/
|
||||
private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
|
||||
int[] vals = r.getIntArray(resNum);
|
||||
int size = vals.length;
|
||||
ArrayList<Integer> list = new ArrayList<Integer>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.add(vals[i]);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a String array asset into a list.
|
||||
*/
|
||||
private static ArrayList<String> loadStringArray(Resources r, int resNum) {
|
||||
String[] labels = r.getStringArray(resNum);
|
||||
ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
|
||||
return list;
|
||||
}
|
||||
|
||||
private void sendAccessibilityEventIfQueryDone(int token) {
|
||||
mCurrentQuery |= token;
|
||||
if (mCurrentQuery == TOKEN_QUERY_ALL) {
|
||||
sendAccessibilityEvent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
@ -1029,19 +867,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
return mView;
|
||||
}
|
||||
|
||||
private final Runnable onDeleteRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (EventInfoFragment.this.mIsPaused) {
|
||||
mDismissOnResume = true;
|
||||
return;
|
||||
}
|
||||
if (EventInfoFragment.this.isVisible()) {
|
||||
EventInfoFragment.this.dismiss();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void updateTitle() {
|
||||
Resources res = getActivity().getResources();
|
||||
if (mCanModifyCalendar && !mIsOrganizer) {
|
||||
@ -1408,38 +1233,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
Utils.UNDO_DELAY);
|
||||
}
|
||||
|
||||
public static int getResponseFromButtonId(int buttonId) {
|
||||
int response;
|
||||
if (buttonId == R.id.response_yes) {
|
||||
response = Attendees.ATTENDEE_STATUS_ACCEPTED;
|
||||
} else if (buttonId == R.id.response_maybe) {
|
||||
response = Attendees.ATTENDEE_STATUS_TENTATIVE;
|
||||
} else if (buttonId == R.id.response_no) {
|
||||
response = Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
} else {
|
||||
response = Attendees.ATTENDEE_STATUS_NONE;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
public static int findButtonIdForResponse(int response) {
|
||||
int buttonId;
|
||||
switch (response) {
|
||||
case Attendees.ATTENDEE_STATUS_ACCEPTED:
|
||||
buttonId = R.id.response_yes;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_TENTATIVE:
|
||||
buttonId = R.id.response_maybe;
|
||||
break;
|
||||
case Attendees.ATTENDEE_STATUS_DECLINED:
|
||||
buttonId = R.id.response_no;
|
||||
break;
|
||||
default:
|
||||
buttonId = -1;
|
||||
}
|
||||
return buttonId;
|
||||
}
|
||||
|
||||
private void doEdit() {
|
||||
Context c = getActivity();
|
||||
// This ensures that we aren't in the process of closing and have been
|
||||
@ -2128,7 +1921,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
EventViewUtils.updateAddReminderButton(mView, mReminderViews, mMaxReminders);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new reminder when the user hits the "add reminder" button. We use the default
|
||||
* reminder time and method.
|
||||
@ -2182,7 +1974,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean saveReminders() {
|
||||
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(3);
|
||||
|
||||
@ -2229,29 +2020,6 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
startActivity(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an integer array asset into a list.
|
||||
*/
|
||||
private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
|
||||
int[] vals = r.getIntArray(resNum);
|
||||
int size = vals.length;
|
||||
ArrayList<Integer> list = new ArrayList<Integer>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.add(vals[i]);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
/**
|
||||
* Loads a String array asset into a list.
|
||||
*/
|
||||
private static ArrayList<String> loadStringArray(Resources r, int resNum) {
|
||||
String[] labels = r.getStringArray(resNum);
|
||||
ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteStarted() {
|
||||
mEventDeletionStarted = true;
|
||||
@ -2277,9 +2045,11 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
public long getStartMillis() {
|
||||
return mStartMillis;
|
||||
}
|
||||
|
||||
public long getEndMillis() {
|
||||
return mEndMillis;
|
||||
}
|
||||
|
||||
private void setDialogSize(Resources r) {
|
||||
mDialogWidth = (int)r.getDimension(R.dimen.event_info_dialog_width);
|
||||
mDialogHeight = (int)r.getDimension(R.dimen.event_info_dialog_height);
|
||||
@ -2291,4 +2061,191 @@ public class EventInfoFragment extends DialogFragment implements OnCheckedChange
|
||||
mCurrentColorKey = mDisplayColorKeyMap.get(color);
|
||||
mHeadlines.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
private class QueryHandler extends AsyncQueryService {
|
||||
public QueryHandler(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
// if the activity is finishing, then close the cursor and return
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null || activity.isFinishing()) {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (token) {
|
||||
case TOKEN_QUERY_EVENT:
|
||||
mEventCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
if (initEventCursor()) {
|
||||
// The cursor is empty. This can happen if the event was
|
||||
// deleted.
|
||||
// FRAG_TODO we should no longer rely on Activity.finish()
|
||||
activity.finish();
|
||||
return;
|
||||
}
|
||||
if (!mCalendarColorInitialized) {
|
||||
mCalendarColor = Utils.getDisplayColorFromColor(
|
||||
mEventCursor.getInt(EVENT_INDEX_CALENDAR_COLOR));
|
||||
mCalendarColorInitialized = true;
|
||||
}
|
||||
|
||||
if (!mOriginalColorInitialized) {
|
||||
mOriginalColor = mEventCursor.isNull(EVENT_INDEX_EVENT_COLOR)
|
||||
? mCalendarColor : Utils.getDisplayColorFromColor(
|
||||
mEventCursor.getInt(EVENT_INDEX_EVENT_COLOR));
|
||||
mOriginalColorInitialized = true;
|
||||
}
|
||||
|
||||
if (!mCurrentColorInitialized) {
|
||||
mCurrentColor = mOriginalColor;
|
||||
mCurrentColorInitialized = true;
|
||||
}
|
||||
|
||||
updateEvent(mView);
|
||||
prepareReminders();
|
||||
|
||||
// start calendar query
|
||||
Uri uri = Calendars.CONTENT_URI;
|
||||
String[] args = new String[]{
|
||||
Long.toString(mEventCursor.getLong(EVENT_INDEX_CALENDAR_ID))};
|
||||
startQuery(TOKEN_QUERY_CALENDARS, null, uri, CALENDARS_PROJECTION,
|
||||
CALENDARS_WHERE, args, null);
|
||||
break;
|
||||
case TOKEN_QUERY_CALENDARS:
|
||||
mCalendarsCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
updateCalendar(mView);
|
||||
// FRAG_TODO fragments shouldn't set the title anymore
|
||||
updateTitle();
|
||||
|
||||
args = new String[]{
|
||||
mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME),
|
||||
mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_TYPE)};
|
||||
uri = Colors.CONTENT_URI;
|
||||
startQuery(TOKEN_QUERY_COLORS, null, uri, COLORS_PROJECTION, COLORS_WHERE, args,
|
||||
null);
|
||||
|
||||
if (!mIsBusyFreeCalendar) {
|
||||
args = new String[]{Long.toString(mEventId)};
|
||||
|
||||
// start attendees query
|
||||
uri = Attendees.CONTENT_URI;
|
||||
startQuery(TOKEN_QUERY_ATTENDEES, null, uri, ATTENDEES_PROJECTION,
|
||||
ATTENDEES_WHERE, args, ATTENDEES_SORT_ORDER);
|
||||
} else {
|
||||
sendAccessibilityEventIfQueryDone(TOKEN_QUERY_ATTENDEES);
|
||||
}
|
||||
if (mHasAlarm) {
|
||||
// start reminders query
|
||||
args = new String[]{Long.toString(mEventId)};
|
||||
uri = Reminders.CONTENT_URI;
|
||||
startQuery(TOKEN_QUERY_REMINDERS, null, uri,
|
||||
REMINDERS_PROJECTION, REMINDERS_WHERE, args, null);
|
||||
} else {
|
||||
sendAccessibilityEventIfQueryDone(TOKEN_QUERY_REMINDERS);
|
||||
}
|
||||
break;
|
||||
case TOKEN_QUERY_COLORS:
|
||||
ArrayList<Integer> colors = new ArrayList<Integer>();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
int colorKey = cursor.getInt(COLORS_INDEX_COLOR_KEY);
|
||||
int rawColor = cursor.getInt(COLORS_INDEX_COLOR);
|
||||
int displayColor = Utils.getDisplayColorFromColor(rawColor);
|
||||
mDisplayColorKeyMap.put(displayColor, colorKey);
|
||||
colors.add(displayColor);
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
Integer[] sortedColors = new Integer[colors.size()];
|
||||
Arrays.sort(colors.toArray(sortedColors), new HsvColorComparator());
|
||||
mColors = new int[sortedColors.length];
|
||||
for (int i = 0; i < sortedColors.length; i++) {
|
||||
mColors[i] = sortedColors[i].intValue();
|
||||
|
||||
float[] hsv = new float[3];
|
||||
Color.colorToHSV(mColors[i], hsv);
|
||||
if (DEBUG) {
|
||||
Log.d("Color", "H:" + hsv[0] + ",S:" + hsv[1] + ",V:" + hsv[2]);
|
||||
}
|
||||
}
|
||||
if (mCanModifyCalendar) {
|
||||
View button = mView.findViewById(R.id.change_color);
|
||||
if (button != null && mColors.length > 0) {
|
||||
button.setEnabled(true);
|
||||
button.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
updateMenu();
|
||||
break;
|
||||
case TOKEN_QUERY_ATTENDEES:
|
||||
mAttendeesCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
initAttendeesCursor(mView);
|
||||
updateResponse(mView);
|
||||
break;
|
||||
case TOKEN_QUERY_REMINDERS:
|
||||
mRemindersCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
initReminders(mView, mRemindersCursor);
|
||||
break;
|
||||
case TOKEN_QUERY_VISIBLE_CALENDARS:
|
||||
if (cursor.getCount() > 1) {
|
||||
// Start duplicate calendars query to detect whether to add the calendar
|
||||
// email to the calendar owner display.
|
||||
String displayName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
|
||||
mHandler.startQuery(TOKEN_QUERY_DUPLICATE_CALENDARS, null,
|
||||
Calendars.CONTENT_URI, CALENDARS_PROJECTION,
|
||||
CALENDARS_DUPLICATE_NAME_WHERE, new String[]{displayName}, null);
|
||||
} else {
|
||||
// Don't need to display the calendar owner when there is only a single
|
||||
// calendar. Skip the duplicate calendars query.
|
||||
setVisibilityCommon(mView, R.id.calendar_container, View.GONE);
|
||||
mCurrentQuery |= TOKEN_QUERY_DUPLICATE_CALENDARS;
|
||||
}
|
||||
break;
|
||||
case TOKEN_QUERY_DUPLICATE_CALENDARS:
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
|
||||
// Calendar display name
|
||||
String calendarName = mCalendarsCursor.getString(CALENDARS_INDEX_DISPLAY_NAME);
|
||||
sb.append(calendarName);
|
||||
|
||||
// Show email account if display name is not unique and
|
||||
// display name != email
|
||||
String email = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
|
||||
if (cursor.getCount() > 1 && !calendarName.equalsIgnoreCase(email) &&
|
||||
Utils.isValidEmail(email)) {
|
||||
sb.append(" (").append(email).append(")");
|
||||
}
|
||||
|
||||
setVisibilityCommon(mView, R.id.calendar_container, View.VISIBLE);
|
||||
setTextCommon(mView, R.id.calendar_name, sb);
|
||||
break;
|
||||
}
|
||||
cursor.close();
|
||||
sendAccessibilityEventIfQueryDone(token);
|
||||
|
||||
// All queries are done, show the view.
|
||||
if (mCurrentQuery == TOKEN_QUERY_ALL) {
|
||||
if (mLoadingMsgView.getAlpha() == 1) {
|
||||
// Loading message is showing, let it stay a bit more (to prevent
|
||||
// flashing) by adding a start delay to the event animation
|
||||
long timeDiff = LOADING_MSG_MIN_DISPLAY_TIME - (System.currentTimeMillis() -
|
||||
mLoadingMsgStartTime);
|
||||
if (timeDiff > 0) {
|
||||
mAnimateAlpha.setStartDelay(timeDiff);
|
||||
}
|
||||
}
|
||||
if (!mAnimateAlpha.isRunning() && !mAnimateAlpha.isStarted() && !mNoCrossFade) {
|
||||
mAnimateAlpha.start();
|
||||
} else {
|
||||
mScrollView.setAlpha(1);
|
||||
mLoadingMsgView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
@ -42,6 +40,83 @@ public class EventLoader {
|
||||
private LoaderThread mLoaderThread;
|
||||
private ContentResolver mResolver;
|
||||
|
||||
public EventLoader(Context context) {
|
||||
mContext = context;
|
||||
mLoaderQueue = new LinkedBlockingQueue<LoadRequest>();
|
||||
mResolver = context.getContentResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from the activity's onResume()
|
||||
*/
|
||||
public void startBackgroundThread() {
|
||||
mLoaderThread = new LoaderThread(mLoaderQueue, this);
|
||||
mLoaderThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from the activity's onPause()
|
||||
*/
|
||||
public void stopBackgroundThread() {
|
||||
mLoaderThread.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads "numDays" days worth of events, starting at start, into events.
|
||||
* Posts uiCallback to the {@link Handler} for this view, which will run in the UI thread.
|
||||
* Reuses an existing background thread, if events were already being loaded in the background.
|
||||
* NOTE: events and uiCallback are not used if an existing background thread gets reused --
|
||||
* the ones that were passed in on the call that results in the background thread getting
|
||||
* created are used, and the most recent call's worth of data is loaded into events and posted
|
||||
* via the uiCallback.
|
||||
*/
|
||||
public void loadEventsInBackground(final int numDays, final ArrayList<Event> events,
|
||||
int startDay, final Runnable successCallback, final Runnable cancelCallback) {
|
||||
|
||||
// Increment the sequence number for requests. We don't care if the
|
||||
// sequence numbers wrap around because we test for equality with the
|
||||
// latest one.
|
||||
int id = mSequenceNumber.incrementAndGet();
|
||||
|
||||
// Send the load request to the background thread
|
||||
LoadEventsRequest request = new LoadEventsRequest(id, startDay, numDays,
|
||||
events, successCallback, cancelCallback);
|
||||
|
||||
try {
|
||||
mLoaderQueue.put(request);
|
||||
} catch (InterruptedException ex) {
|
||||
// The put() method fails with InterruptedException if the
|
||||
// queue is full. This should never happen because the queue
|
||||
// has no limit.
|
||||
Log.e("Cal", "loadEventsInBackground() interrupted!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request for the days with events to be marked. Loads "numDays"
|
||||
* worth of days, starting at start, and fills in eventDays to express which
|
||||
* days have events.
|
||||
*
|
||||
* @param startDay First day to check for events
|
||||
* @param numDays Days following the start day to check
|
||||
* @param eventDay Whether or not an event exists on that day
|
||||
* @param uiCallback What to do when done (log data, redraw screen)
|
||||
*/
|
||||
void loadEventDaysInBackground(int startDay, int numDays, boolean[] eventDays,
|
||||
final Runnable uiCallback) {
|
||||
// Send load request to the background thread
|
||||
LoadEventDaysRequest request = new LoadEventDaysRequest(startDay, numDays,
|
||||
eventDays, uiCallback);
|
||||
try {
|
||||
mLoaderQueue.put(request);
|
||||
} catch (InterruptedException ex) {
|
||||
// The put() method fails with InterruptedException if the
|
||||
// queue is full. This should never happen because the queue
|
||||
// has no limit.
|
||||
Log.e("Cal", "loadEventDaysInBackground() interrupted!");
|
||||
}
|
||||
}
|
||||
|
||||
private static interface LoadRequest {
|
||||
public void processRequest(EventLoader eventLoader);
|
||||
public void skipRequest(EventLoader eventLoader);
|
||||
@ -62,17 +137,16 @@ public class EventLoader {
|
||||
*
|
||||
*/
|
||||
private static class LoadEventDaysRequest implements LoadRequest {
|
||||
public int startDay;
|
||||
public int numDays;
|
||||
public boolean[] eventDays;
|
||||
public Runnable uiCallback;
|
||||
|
||||
/**
|
||||
* The projection used by the EventDays query.
|
||||
*/
|
||||
private static final String[] PROJECTION = {
|
||||
CalendarContract.EventDays.STARTDAY, CalendarContract.EventDays.ENDDAY
|
||||
};
|
||||
public int startDay;
|
||||
public int numDays;
|
||||
public boolean[] eventDays;
|
||||
public Runnable uiCallback;
|
||||
|
||||
public LoadEventDaysRequest(int startDay, int numDays, boolean[] eventDays,
|
||||
final Runnable uiCallback)
|
||||
@ -207,82 +281,4 @@ public class EventLoader {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EventLoader(Context context) {
|
||||
mContext = context;
|
||||
mLoaderQueue = new LinkedBlockingQueue<LoadRequest>();
|
||||
mResolver = context.getContentResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from the activity's onResume()
|
||||
*/
|
||||
public void startBackgroundThread() {
|
||||
mLoaderThread = new LoaderThread(mLoaderQueue, this);
|
||||
mLoaderThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from the activity's onPause()
|
||||
*/
|
||||
public void stopBackgroundThread() {
|
||||
mLoaderThread.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads "numDays" days worth of events, starting at start, into events.
|
||||
* Posts uiCallback to the {@link Handler} for this view, which will run in the UI thread.
|
||||
* Reuses an existing background thread, if events were already being loaded in the background.
|
||||
* NOTE: events and uiCallback are not used if an existing background thread gets reused --
|
||||
* the ones that were passed in on the call that results in the background thread getting
|
||||
* created are used, and the most recent call's worth of data is loaded into events and posted
|
||||
* via the uiCallback.
|
||||
*/
|
||||
public void loadEventsInBackground(final int numDays, final ArrayList<Event> events,
|
||||
int startDay, final Runnable successCallback, final Runnable cancelCallback) {
|
||||
|
||||
// Increment the sequence number for requests. We don't care if the
|
||||
// sequence numbers wrap around because we test for equality with the
|
||||
// latest one.
|
||||
int id = mSequenceNumber.incrementAndGet();
|
||||
|
||||
// Send the load request to the background thread
|
||||
LoadEventsRequest request = new LoadEventsRequest(id, startDay, numDays,
|
||||
events, successCallback, cancelCallback);
|
||||
|
||||
try {
|
||||
mLoaderQueue.put(request);
|
||||
} catch (InterruptedException ex) {
|
||||
// The put() method fails with InterruptedException if the
|
||||
// queue is full. This should never happen because the queue
|
||||
// has no limit.
|
||||
Log.e("Cal", "loadEventsInBackground() interrupted!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request for the days with events to be marked. Loads "numDays"
|
||||
* worth of days, starting at start, and fills in eventDays to express which
|
||||
* days have events.
|
||||
*
|
||||
* @param startDay First day to check for events
|
||||
* @param numDays Days following the start day to check
|
||||
* @param eventDay Whether or not an event exists on that day
|
||||
* @param uiCallback What to do when done (log data, redraw screen)
|
||||
*/
|
||||
void loadEventDaysInBackground(int startDay, int numDays, boolean[] eventDays,
|
||||
final Runnable uiCallback)
|
||||
{
|
||||
// Send load request to the background thread
|
||||
LoadEventDaysRequest request = new LoadEventDaysRequest(startDay, numDays,
|
||||
eventDays, uiCallback);
|
||||
try {
|
||||
mLoaderQueue.put(request);
|
||||
} catch (InterruptedException ex) {
|
||||
// The put() method fails with InterruptedException if the
|
||||
// queue is full. This should never happen because the queue
|
||||
// has no limit.
|
||||
Log.e("Cal", "loadEventDaysInBackground() interrupted!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.text.format.DateUtils;
|
||||
@ -28,6 +26,8 @@ import com.android.calendarcommon2.EventRecurrence;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class EventRecurrenceFormatter
|
||||
{
|
||||
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
@ -27,6 +25,8 @@ import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class ExpandableTextView extends LinearLayout implements OnClickListener {
|
||||
|
||||
TextView mTv;
|
||||
@ -110,6 +110,13 @@ public class ExpandableTextView extends LinearLayout implements OnClickListener
|
||||
mButton.setOnClickListener(this);
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
if (mTv == null) {
|
||||
return "";
|
||||
}
|
||||
return mTv.getText();
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
mRelayout = true;
|
||||
if (mTv == null) {
|
||||
@ -119,11 +126,4 @@ public class ExpandableTextView extends LinearLayout implements OnClickListener
|
||||
mTv.setText(trimmedText);
|
||||
this.setVisibility(trimmedText.length() == 0 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
if (mTv == null) {
|
||||
return "";
|
||||
}
|
||||
return mTv.getText();
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Bundle;
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.backup.BackupManager;
|
||||
@ -50,50 +48,37 @@ import android.widget.Toast;
|
||||
|
||||
import com.android.calendar.alerts.AlertReceiver;
|
||||
import com.android.calendar.event.EventViewUtils;
|
||||
|
||||
import com.android.timezonepicker.TimeZoneInfo;
|
||||
import com.android.timezonepicker.TimeZonePickerDialog;
|
||||
import com.android.timezonepicker.TimeZonePickerDialog.OnTimeZoneSetListener;
|
||||
import com.android.timezonepicker.TimeZonePickerUtils;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class GeneralPreferences extends PreferenceFragment implements
|
||||
OnSharedPreferenceChangeListener, OnPreferenceChangeListener, OnTimeZoneSetListener {
|
||||
// The name of the shared preferences file. This name must be maintained for historical
|
||||
// reasons, as it's what PreferenceManager assigned the first time the file was created.
|
||||
static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
|
||||
static final String SHARED_PREFS_NAME_NO_BACKUP = "com.android.calendar_preferences_no_backup";
|
||||
|
||||
private static final String FRAG_TAG_TIME_ZONE_PICKER = "TimeZonePicker";
|
||||
|
||||
// Preference keys
|
||||
public static final String KEY_HIDE_DECLINED = "preferences_hide_declined";
|
||||
public static final String KEY_WEEK_START_DAY = "preferences_week_start_day";
|
||||
public static final String KEY_SHOW_WEEK_NUM = "preferences_show_week_num";
|
||||
public static final String KEY_DAYS_PER_WEEK = "preferences_days_per_week";
|
||||
public static final String KEY_SKIP_SETUP = "preferences_skip_setup";
|
||||
|
||||
public static final String KEY_CLEAR_SEARCH_HISTORY = "preferences_clear_search_history";
|
||||
|
||||
public static final String KEY_ALERTS_CATEGORY = "preferences_alerts_category";
|
||||
public static final String KEY_ALERTS = "preferences_alerts";
|
||||
public static final String KEY_ALERTS_VIBRATE = "preferences_alerts_vibrate";
|
||||
public static final String KEY_ALERTS_RINGTONE = "preferences_alerts_ringtone";
|
||||
public static final String KEY_ALERTS_POPUP = "preferences_alerts_popup";
|
||||
|
||||
public static final String KEY_SHOW_CONTROLS = "preferences_show_controls";
|
||||
|
||||
public static final String KEY_DEFAULT_REMINDER = "preferences_default_reminder";
|
||||
public static final int NO_REMINDER = -1;
|
||||
public static final String NO_REMINDER_STRING = "-1";
|
||||
public static final int REMINDER_DEFAULT_TIME = 10; // in minutes
|
||||
|
||||
public static final String KEY_USE_CUSTOM_SNOOZE_DELAY = "preferences_custom_snooze_delay";
|
||||
public static final String KEY_DEFAULT_SNOOZE_DELAY = "preferences_default_snooze_delay";
|
||||
public static final int SNOOZE_DELAY_DEFAULT_TIME = 5; // in minutes
|
||||
|
||||
public static final String KEY_DEFAULT_CELL_HEIGHT = "preferences_default_cell_height";
|
||||
public static final String KEY_VERSION = "preferences_version";
|
||||
|
||||
/** Key to SharePreference for default view (CalendarController.ViewType) */
|
||||
public static final String KEY_START_VIEW = "preferred_startView";
|
||||
/**
|
||||
@ -102,28 +87,29 @@ public class GeneralPreferences extends PreferenceFragment implements
|
||||
*/
|
||||
public static final String KEY_DETAILED_VIEW = "preferred_detailedView";
|
||||
public static final String KEY_DEFAULT_CALENDAR = "preference_defaultCalendar";
|
||||
|
||||
// These must be in sync with the array preferences_week_start_day_values
|
||||
public static final String WEEK_START_DEFAULT = "-1";
|
||||
public static final String WEEK_START_SATURDAY = "7";
|
||||
public static final String WEEK_START_SUNDAY = "1";
|
||||
public static final String WEEK_START_MONDAY = "2";
|
||||
|
||||
// These keys are kept to enable migrating users from previous versions
|
||||
private static final String KEY_ALERTS_TYPE = "preferences_alerts_type";
|
||||
private static final String ALERT_TYPE_ALERTS = "0";
|
||||
private static final String ALERT_TYPE_STATUS_BAR = "1";
|
||||
private static final String ALERT_TYPE_OFF = "2";
|
||||
static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
|
||||
static final String KEY_HOME_TZ = "preferences_home_tz";
|
||||
|
||||
// Default preference values
|
||||
public static final int DEFAULT_START_VIEW = CalendarController.ViewType.WEEK;
|
||||
public static final int DEFAULT_DETAILED_VIEW = CalendarController.ViewType.DAY;
|
||||
public static final boolean DEFAULT_SHOW_WEEK_NUM = false;
|
||||
// This should match the XML file.
|
||||
public static final String DEFAULT_RINGTONE = "content://settings/system/notification_sound";
|
||||
|
||||
// The name of the shared preferences file. This name must be maintained for historical
|
||||
// reasons, as it's what PreferenceManager assigned the first time the file was created.
|
||||
static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
|
||||
static final String SHARED_PREFS_NAME_NO_BACKUP = "com.android.calendar_preferences_no_backup";
|
||||
static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
|
||||
static final String KEY_HOME_TZ = "preferences_home_tz";
|
||||
private static final String FRAG_TAG_TIME_ZONE_PICKER = "TimeZonePicker";
|
||||
// These keys are kept to enable migrating users from previous versions
|
||||
private static final String KEY_ALERTS_TYPE = "preferences_alerts_type";
|
||||
private static final String ALERT_TYPE_ALERTS = "0";
|
||||
private static final String ALERT_TYPE_STATUS_BAR = "1";
|
||||
private static final String ALERT_TYPE_OFF = "2";
|
||||
CheckBoxPreference mAlert;
|
||||
CheckBoxPreference mVibrate;
|
||||
RingtonePreference mRingtone;
|
||||
|
@ -17,16 +17,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_NONE;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentUris;
|
||||
@ -43,10 +33,17 @@ import android.util.Log;
|
||||
import com.android.calendarcommon2.DateException;
|
||||
import com.android.calendarcommon2.Duration;
|
||||
|
||||
public class GoogleCalendarUriIntentFilter extends Activity {
|
||||
private static final String TAG = "GoogleCalendarUriIntentFilter";
|
||||
static final boolean debug = false;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_NONE;
|
||||
import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
||||
public class GoogleCalendarUriIntentFilter extends Activity {
|
||||
static final boolean debug = false;
|
||||
private static final String TAG = "GoogleCalendarUriIntentFilter";
|
||||
private static final int EVENT_INDEX_ID = 0;
|
||||
private static final int EVENT_INDEX_START = 1;
|
||||
private static final int EVENT_INDEX_END = 2;
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@ -25,6 +23,8 @@ import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.widget.Button;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A button with more than two states. When the button is pressed
|
||||
|
@ -16,10 +16,7 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
@ -37,14 +34,9 @@ import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
public class OtherPreferences extends PreferenceFragment implements OnPreferenceChangeListener{
|
||||
private static final String TAG = "CalendarOtherPreferences";
|
||||
|
||||
// The name of the shared preferences file. This name must be maintained for
|
||||
// historical reasons, as it's what PreferenceManager assigned the first
|
||||
// time the file was created.
|
||||
static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class OtherPreferences extends PreferenceFragment implements OnPreferenceChangeListener {
|
||||
// Must be the same keys that are used in the other_preferences.xml file.
|
||||
public static final String KEY_OTHER_COPY_DB = "preferences_copy_db";
|
||||
public static final String KEY_OTHER_QUIET_HOURS = "preferences_reminders_quiet_hours";
|
||||
@ -62,12 +54,15 @@ public class OtherPreferences extends PreferenceFragment implements OnPreferenc
|
||||
public static final String KEY_OTHER_QUIET_HOURS_END_MINUTE =
|
||||
"preferences_reminders_quiet_hours_end_minute";
|
||||
public static final String KEY_OTHER_1 = "preferences_tardis_1";
|
||||
|
||||
public static final int QUIET_HOURS_DEFAULT_START_HOUR = 22;
|
||||
public static final int QUIET_HOURS_DEFAULT_START_MINUTE = 0;
|
||||
public static final int QUIET_HOURS_DEFAULT_END_HOUR = 8;
|
||||
public static final int QUIET_HOURS_DEFAULT_END_MINUTE = 0;
|
||||
|
||||
// The name of the shared preferences file. This name must be maintained for
|
||||
// historical reasons, as it's what PreferenceManager assigned the first
|
||||
// time the file was created.
|
||||
static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
|
||||
private static final String TAG = "CalendarOtherPreferences";
|
||||
private static final int START_LISTENER = 1;
|
||||
private static final int END_LISTENER = 2;
|
||||
private static final String format24Hour = "%H:%M";
|
||||
@ -177,40 +172,6 @@ public class OtherPreferences extends PreferenceFragment implements OnPreferenc
|
||||
return true;
|
||||
}
|
||||
|
||||
private class TimeSetListener implements TimePickerDialog.OnTimeSetListener {
|
||||
private int mListenerId;
|
||||
|
||||
public TimeSetListener(int listenerId) {
|
||||
mListenerId = listenerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
|
||||
mTimePickerDialog = null;
|
||||
|
||||
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
String summary = formatTime(hourOfDay, minute);
|
||||
switch (mListenerId) {
|
||||
case (START_LISTENER):
|
||||
mQuietHoursStart.setSummary(summary);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_START_HOUR, hourOfDay);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_START_MINUTE, minute);
|
||||
break;
|
||||
case (END_LISTENER):
|
||||
mQuietHoursEnd.setSummary(summary);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_END_HOUR, hourOfDay);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_END_MINUTE, minute);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Set time for unknown listener: "+mListenerId);
|
||||
}
|
||||
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hourOfDay the hour of the day (0-24)
|
||||
* @param minute
|
||||
@ -250,4 +211,38 @@ public class OtherPreferences extends PreferenceFragment implements OnPreferenc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TimeSetListener implements TimePickerDialog.OnTimeSetListener {
|
||||
private int mListenerId;
|
||||
|
||||
public TimeSetListener(int listenerId) {
|
||||
mListenerId = listenerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
|
||||
mTimePickerDialog = null;
|
||||
|
||||
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
String summary = formatTime(hourOfDay, minute);
|
||||
switch (mListenerId) {
|
||||
case (START_LISTENER):
|
||||
mQuietHoursStart.setSummary(summary);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_START_HOUR, hourOfDay);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_START_MINUTE, minute);
|
||||
break;
|
||||
case (END_LISTENER):
|
||||
mQuietHoursEnd.setSummary(summary);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_END_HOUR, hourOfDay);
|
||||
editor.putInt(KEY_OTHER_QUIET_HOURS_END_MINUTE, minute);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Set time for unknown listener: " + mListenerId);
|
||||
}
|
||||
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.preference.EditTextPreference;
|
||||
@ -29,6 +27,8 @@ import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* Fragment to facilitate editing of quick responses when emailing guests
|
||||
*
|
||||
|
@ -16,13 +16,11 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import com.android.ex.chips.BaseRecipientAdapter;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.ex.chips.BaseRecipientAdapter;
|
||||
|
||||
public class RecipientAdapter extends BaseRecipientAdapter {
|
||||
public RecipientAdapter(Context context) {
|
||||
super(context);
|
||||
|
@ -43,7 +43,7 @@ import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
import com.android.calendar.agenda.AgendaFragment;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.calendar;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
@ -63,65 +61,30 @@ public class StickyHeaderListView extends FrameLayout implements OnScrollListene
|
||||
protected View mDummyHeader = null; // A invisible header used when a section has no header
|
||||
protected ListView mListView = null;
|
||||
protected ListView.OnScrollListener mListener = null;
|
||||
|
||||
private int mSeparatorWidth;
|
||||
private View mSeparatorView;
|
||||
private int mLastStickyHeaderHeight = 0;
|
||||
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// protected DataSetObserver mListDataObserver = null;
|
||||
|
||||
|
||||
protected int mCurrentSectionPos = -1; // Position of section that has its header on the
|
||||
// top of the view
|
||||
protected int mNextSectionPosition = -1; // Position of next section's header
|
||||
protected int mListViewHeadersCount = 0;
|
||||
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// protected DataSetObserver mListDataObserver = null;
|
||||
private int mSeparatorWidth;
|
||||
private View mSeparatorView;
|
||||
private int mLastStickyHeaderHeight = 0;
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by the ListView adapter to provide headers locations
|
||||
* and number of items under each header.
|
||||
* Constructor
|
||||
*
|
||||
* @param context - application context.
|
||||
* @param attrs - layout attributes.
|
||||
*/
|
||||
public interface HeaderIndexer {
|
||||
/**
|
||||
* Calculates the position of the header of a specific item in the adapter's data set.
|
||||
* For example: Assuming you have a list with albums and songs names:
|
||||
* Album A, song 1, song 2, ...., song 10, Album B, song 1, ..., song 7. A call to
|
||||
* this method with the position of song 5 in Album B, should return the position
|
||||
* of Album B.
|
||||
* @param position - Position of the item in the ListView dataset
|
||||
* @return Position of header. -1 if the is no header
|
||||
*/
|
||||
|
||||
int getHeaderPositionFromItemPosition(int position);
|
||||
|
||||
/**
|
||||
* Calculates the number of items in the section defined by the header (not including
|
||||
* the header).
|
||||
* For example: A list with albums and songs, the method should return
|
||||
* the number of songs names (without the album name).
|
||||
*
|
||||
* @param headerPosition - the value returned by 'getHeaderPositionFromItemPosition'
|
||||
* @return Number of items. -1 on error.
|
||||
*/
|
||||
int getHeaderItemsNumber(int headerPosition);
|
||||
public StickyHeaderListView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// createDataListener();
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* Interface that is used to update the sticky header's height
|
||||
*
|
||||
*/
|
||||
public interface HeaderHeightListener {
|
||||
|
||||
/***
|
||||
* Updated a change in the sticky header's size
|
||||
*
|
||||
* @param height - new height of sticky header
|
||||
*/
|
||||
void OnHeaderHeightChanged(int height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the adapter to be used by the class to get views of headers
|
||||
*
|
||||
@ -181,29 +144,6 @@ public class StickyHeaderListView extends FrameLayout implements OnScrollListene
|
||||
mHeaderHeightListener = listener;
|
||||
}
|
||||
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// protected void createDataListener() {
|
||||
// mListDataObserver = new DataSetObserver() {
|
||||
// @Override
|
||||
// public void onChanged() {
|
||||
// onDataChanged();
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context - application context.
|
||||
* @param attrs - layout attributes.
|
||||
*/
|
||||
public StickyHeaderListView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// createDataListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll status changes listener
|
||||
*
|
||||
@ -217,6 +157,16 @@ public class StickyHeaderListView extends FrameLayout implements OnScrollListene
|
||||
}
|
||||
}
|
||||
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// protected void createDataListener() {
|
||||
// mListDataObserver = new DataSetObserver() {
|
||||
// @Override
|
||||
// public void onChanged() {
|
||||
// onDataChanged();
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
/**
|
||||
* Scroll events listener
|
||||
*
|
||||
@ -361,13 +311,6 @@ public class StickyHeaderListView extends FrameLayout implements OnScrollListene
|
||||
mDoHeaderReset = true;
|
||||
}
|
||||
|
||||
|
||||
// Resets the sticky header when the adapter data set was changed
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// protected void onDataChanged() {
|
||||
// Should do a call to updateStickyHeader if needed
|
||||
// }
|
||||
|
||||
private void setChildViews() {
|
||||
|
||||
// Find a child ListView (if any)
|
||||
@ -394,4 +337,54 @@ public class StickyHeaderListView extends FrameLayout implements OnScrollListene
|
||||
mChildViewsCreated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by the ListView adapter to provide headers locations
|
||||
* and number of items under each header.
|
||||
*/
|
||||
public interface HeaderIndexer {
|
||||
/**
|
||||
* Calculates the position of the header of a specific item in the adapter's data set.
|
||||
* For example: Assuming you have a list with albums and songs names:
|
||||
* Album A, song 1, song 2, ...., song 10, Album B, song 1, ..., song 7. A call to
|
||||
* this method with the position of song 5 in Album B, should return the position
|
||||
* of Album B.
|
||||
*
|
||||
* @param position - Position of the item in the ListView dataset
|
||||
* @return Position of header. -1 if the is no header
|
||||
*/
|
||||
|
||||
int getHeaderPositionFromItemPosition(int position);
|
||||
|
||||
/**
|
||||
* Calculates the number of items in the section defined by the header (not including
|
||||
* the header).
|
||||
* For example: A list with albums and songs, the method should return
|
||||
* the number of songs names (without the album name).
|
||||
*
|
||||
* @param headerPosition - the value returned by 'getHeaderPositionFromItemPosition'
|
||||
* @return Number of items. -1 on error.
|
||||
*/
|
||||
int getHeaderItemsNumber(int headerPosition);
|
||||
}
|
||||
|
||||
|
||||
// Resets the sticky header when the adapter data set was changed
|
||||
// This code is needed only if dataset changes do not force a call to OnScroll
|
||||
// protected void onDataChanged() {
|
||||
// Should do a call to updateStickyHeader if needed
|
||||
// }
|
||||
|
||||
/***
|
||||
* Interface that is used to update the sticky header's height
|
||||
*/
|
||||
public interface HeaderHeightListener {
|
||||
|
||||
/***
|
||||
* Updated a change in the sticky header's size
|
||||
*
|
||||
* @param height - new height of sticky header
|
||||
*/
|
||||
void OnHeaderHeightChanged(int height);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,8 +53,6 @@ import com.android.calendar.CalendarController.ViewType;
|
||||
import com.android.calendar.CalendarEventModel.ReminderEntry;
|
||||
import com.android.calendar.CalendarUtils.TimeZoneUtils;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
@ -71,6 +69,8 @@ import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
|
||||
public class Utils {
|
||||
|
@ -31,13 +31,14 @@ import android.widget.ResourceCursorAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.ColorChipView;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AgendaAdapter extends ResourceCursorAdapter {
|
||||
private final String mNoTitleLabel;
|
||||
private final Resources mResources;
|
||||
@ -48,37 +49,15 @@ public class AgendaAdapter extends ResourceCursorAdapter {
|
||||
// Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
|
||||
private final Formatter mFormatter;
|
||||
private final StringBuilder mStringBuilder;
|
||||
private float mScale;
|
||||
|
||||
private int COLOR_CHIP_ALL_DAY_HEIGHT;
|
||||
private int COLOR_CHIP_HEIGHT;
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
|
||||
static class ViewHolder {
|
||||
|
||||
public static final int DECLINED_RESPONSE = 0;
|
||||
public static final int TENTATIVE_RESPONSE = 1;
|
||||
public static final int ACCEPTED_RESPONSE = 2;
|
||||
|
||||
/* Event */
|
||||
TextView title;
|
||||
TextView when;
|
||||
TextView where;
|
||||
View selectedMarker;
|
||||
LinearLayout textContainer;
|
||||
long instanceId;
|
||||
ColorChipView colorChip;
|
||||
long startTimeMilli;
|
||||
boolean allDay;
|
||||
boolean grayed;
|
||||
int julianDay;
|
||||
}
|
||||
private float mScale;
|
||||
private int COLOR_CHIP_ALL_DAY_HEIGHT;
|
||||
private int COLOR_CHIP_HEIGHT;
|
||||
|
||||
public AgendaAdapter(Context context, int resource) {
|
||||
super(context, resource, null);
|
||||
@ -263,6 +242,26 @@ public class AgendaAdapter extends ResourceCursorAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
|
||||
public static final int DECLINED_RESPONSE = 0;
|
||||
public static final int TENTATIVE_RESPONSE = 1;
|
||||
public static final int ACCEPTED_RESPONSE = 2;
|
||||
|
||||
/* Event */
|
||||
TextView title;
|
||||
TextView when;
|
||||
TextView where;
|
||||
View selectedMarker;
|
||||
LinearLayout textContainer;
|
||||
long instanceId;
|
||||
ColorChipView colorChip;
|
||||
long startTimeMilli;
|
||||
boolean allDay;
|
||||
boolean grayed;
|
||||
int julianDay;
|
||||
}
|
||||
|
||||
/*
|
||||
public static void updateReminder(View view, Context context, long begin, long eventId) {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
|
@ -28,7 +28,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.agenda.AgendaWindowAdapter.DayAdapterInfo;
|
||||
|
||||
@ -38,29 +37,22 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AgendaByDayAdapter extends BaseAdapter {
|
||||
static final int TYPE_LAST = 2;
|
||||
private static final int TYPE_DAY = 0;
|
||||
private static final int TYPE_MEETING = 1;
|
||||
static final int TYPE_LAST = 2;
|
||||
|
||||
private final Context mContext;
|
||||
private final AgendaAdapter mAgendaAdapter;
|
||||
private final LayoutInflater mInflater;
|
||||
// Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
|
||||
private final Formatter mFormatter;
|
||||
private final StringBuilder mStringBuilder;
|
||||
private ArrayList<RowInfo> mRowInfo;
|
||||
private int mTodayJulianDay;
|
||||
private Time mTmpTime;
|
||||
private String mTimeZone;
|
||||
// Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
|
||||
private final Formatter mFormatter;
|
||||
private final StringBuilder mStringBuilder;
|
||||
|
||||
static class ViewHolder {
|
||||
TextView dayView;
|
||||
TextView dateView;
|
||||
int julianDay;
|
||||
boolean grayed;
|
||||
}
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -94,7 +86,6 @@ public class AgendaByDayAdapter extends BaseAdapter {
|
||||
return mRowInfo.get(position).mEventStartTimeMilli;
|
||||
}
|
||||
|
||||
|
||||
// Returns the position of a header of a specific item
|
||||
public int getHeaderPosition(int position) {
|
||||
if (mRowInfo == null || position >= mRowInfo.size()) {
|
||||
@ -431,69 +422,6 @@ public class AgendaByDayAdapter extends BaseAdapter {
|
||||
mRowInfo = rowInfo;
|
||||
}
|
||||
|
||||
private static class RowInfo {
|
||||
// mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING)
|
||||
final int mType;
|
||||
|
||||
final int mDay; // Julian day
|
||||
final int mPosition; // cursor position (not used for TYPE_DAY)
|
||||
// This is used to mark a day header as the first day with events that is "today"
|
||||
// or later. This flag is used by the adapter to create a view with a visual separator
|
||||
// between the past and the present/future
|
||||
boolean mFirstDayAfterYesterday;
|
||||
final long mEventId;
|
||||
final long mEventStartTimeMilli;
|
||||
final long mEventEndTimeMilli;
|
||||
final long mInstanceId;
|
||||
final boolean mAllDay;
|
||||
|
||||
RowInfo(int type, int julianDay, int position, long id, long startTime, long endTime,
|
||||
long instanceId, boolean allDay) {
|
||||
mType = type;
|
||||
mDay = julianDay;
|
||||
mPosition = position;
|
||||
mEventId = id;
|
||||
mEventStartTimeMilli = startTime;
|
||||
mEventEndTimeMilli = endTime;
|
||||
mFirstDayAfterYesterday = false;
|
||||
mInstanceId = instanceId;
|
||||
mAllDay = allDay;
|
||||
}
|
||||
|
||||
RowInfo(int type, int julianDay) {
|
||||
mType = type;
|
||||
mDay = julianDay;
|
||||
mPosition = 0;
|
||||
mEventId = 0;
|
||||
mEventStartTimeMilli = 0;
|
||||
mEventEndTimeMilli = 0;
|
||||
mFirstDayAfterYesterday = false;
|
||||
mInstanceId = -1;
|
||||
mAllDay = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MultipleDayInfo {
|
||||
final int mPosition;
|
||||
final int mEndDay;
|
||||
final long mEventId;
|
||||
long mEventStartTimeMilli;
|
||||
long mEventEndTimeMilli;
|
||||
final long mInstanceId;
|
||||
final boolean mAllDay;
|
||||
|
||||
MultipleDayInfo(int position, int endDay, long id, long startTime, long endTime,
|
||||
long instanceId, boolean allDay) {
|
||||
mPosition = position;
|
||||
mEndDay = endDay;
|
||||
mEventId = id;
|
||||
mEventStartTimeMilli = startTime;
|
||||
mEventEndTimeMilli = endTime;
|
||||
mInstanceId = instanceId;
|
||||
mAllDay = allDay;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the position in the cursor of the event that best matches the time and Id.
|
||||
* It will try to find the event that has the specified id and start time, if such event
|
||||
@ -588,7 +516,6 @@ public class AgendaByDayAdapter extends BaseAdapter {
|
||||
return minIndex;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a flag indicating if this position is the first day after "yesterday" that has
|
||||
* events in it.
|
||||
@ -681,4 +608,74 @@ public class AgendaByDayAdapter extends BaseAdapter {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
TextView dayView;
|
||||
TextView dateView;
|
||||
int julianDay;
|
||||
boolean grayed;
|
||||
}
|
||||
|
||||
private static class RowInfo {
|
||||
// mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING)
|
||||
final int mType;
|
||||
|
||||
final int mDay; // Julian day
|
||||
final int mPosition; // cursor position (not used for TYPE_DAY)
|
||||
final long mEventId;
|
||||
final long mEventStartTimeMilli;
|
||||
final long mEventEndTimeMilli;
|
||||
final long mInstanceId;
|
||||
final boolean mAllDay;
|
||||
// This is used to mark a day header as the first day with events that is "today"
|
||||
// or later. This flag is used by the adapter to create a view with a visual separator
|
||||
// between the past and the present/future
|
||||
boolean mFirstDayAfterYesterday;
|
||||
|
||||
RowInfo(int type, int julianDay, int position, long id, long startTime, long endTime,
|
||||
long instanceId, boolean allDay) {
|
||||
mType = type;
|
||||
mDay = julianDay;
|
||||
mPosition = position;
|
||||
mEventId = id;
|
||||
mEventStartTimeMilli = startTime;
|
||||
mEventEndTimeMilli = endTime;
|
||||
mFirstDayAfterYesterday = false;
|
||||
mInstanceId = instanceId;
|
||||
mAllDay = allDay;
|
||||
}
|
||||
|
||||
RowInfo(int type, int julianDay) {
|
||||
mType = type;
|
||||
mDay = julianDay;
|
||||
mPosition = 0;
|
||||
mEventId = 0;
|
||||
mEventStartTimeMilli = 0;
|
||||
mEventEndTimeMilli = 0;
|
||||
mFirstDayAfterYesterday = false;
|
||||
mInstanceId = -1;
|
||||
mAllDay = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MultipleDayInfo {
|
||||
final int mPosition;
|
||||
final int mEndDay;
|
||||
final long mEventId;
|
||||
final long mInstanceId;
|
||||
final boolean mAllDay;
|
||||
long mEventStartTimeMilli;
|
||||
long mEventEndTimeMilli;
|
||||
|
||||
MultipleDayInfo(int position, int endDay, long id, long startTime, long endTime,
|
||||
long instanceId, boolean allDay) {
|
||||
mPosition = position;
|
||||
mEndDay = endDay;
|
||||
mEventId = id;
|
||||
mEventStartTimeMilli = startTime;
|
||||
mEventEndTimeMilli = endTime;
|
||||
mInstanceId = instanceId;
|
||||
mAllDay = allDay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,26 +40,35 @@ import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
import com.android.calendar.EventInfoFragment;
|
||||
import com.android.calendar.GeneralPreferences;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.StickyHeaderListView;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AgendaFragment extends Fragment implements CalendarController.EventHandler,
|
||||
OnScrollListener {
|
||||
|
||||
private static final String TAG = AgendaFragment.class.getSimpleName();
|
||||
private static boolean DEBUG = false;
|
||||
|
||||
protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
|
||||
protected static final String BUNDLE_KEY_RESTORE_INSTANCE_ID = "key_restore_instance_id";
|
||||
|
||||
private static final String TAG = AgendaFragment.class.getSimpleName();
|
||||
private static boolean DEBUG = false;
|
||||
private final Time mTime;
|
||||
private final long mInitialTimeMillis;
|
||||
// Tracks the time of the top visible view in order to send UPDATE_TITLE messages to the action
|
||||
// bar.
|
||||
int mJulianDayOnTop = -1;
|
||||
private AgendaListView mAgendaListView;
|
||||
private Activity mActivity;
|
||||
private final Time mTime;
|
||||
private String mTimeZone;
|
||||
private final long mInitialTimeMillis;
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTimeZone = Utils.getTimeZone(getActivity(), this);
|
||||
mTime.switchTimezone(mTimeZone);
|
||||
}
|
||||
};
|
||||
private boolean mShowEventDetailsWithAgenda;
|
||||
private CalendarController mController;
|
||||
private EventInfoFragment mEventFragment;
|
||||
@ -71,26 +80,13 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
|
||||
private AgendaWindowAdapter mAdapter = null;
|
||||
private boolean mForceReplace = true;
|
||||
private long mLastShownEventId = -1;
|
||||
|
||||
|
||||
|
||||
// Tracks the time of the top visible view in order to send UPDATE_TITLE messages to the action
|
||||
// bar.
|
||||
int mJulianDayOnTop = -1;
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTimeZone = Utils.getTimeZone(getActivity(), this);
|
||||
mTime.switchTimezone(mTimeZone);
|
||||
}
|
||||
};
|
||||
private long mLastHandledEventId = -1;
|
||||
private Time mLastHandledEventTime = null;
|
||||
|
||||
public AgendaFragment() {
|
||||
this(0, false);
|
||||
}
|
||||
|
||||
|
||||
// timeMillis - time of first event to show
|
||||
// usedForSearch - indicates if this fragment is used in the search fragment
|
||||
public AgendaFragment(long timeMillis, boolean usedForSearch) {
|
||||
@ -326,7 +322,7 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
|
||||
return;
|
||||
}
|
||||
mAgendaListView.goTo(mTime, event.id, mQuery, false,
|
||||
((event.extraLong & CalendarController.EXTRA_GOTO_TODAY) != 0 &&
|
||||
((event.extraLong & CalendarController.EXTRA_GOTO_TODAY) != 0 &&
|
||||
mShowEventDetailsWithAgenda) ? true : false);
|
||||
AgendaAdapter.ViewHolder vh = mAgendaListView.getSelectedViewHolder();
|
||||
// Make sure that on the first time the event info is shown to recreate it
|
||||
@ -359,8 +355,6 @@ public class AgendaFragment extends Fragment implements CalendarController.Event
|
||||
return EventType.GO_TO | EventType.EVENTS_CHANGED | ((mUsedForSearch)?EventType.SEARCH:0);
|
||||
}
|
||||
|
||||
private long mLastHandledEventId = -1;
|
||||
private Time mLastHandledEventTime = null;
|
||||
@Override
|
||||
public void handleEvent(EventInfo event) {
|
||||
if (event.eventType == EventType.GO_TO) {
|
||||
|
@ -16,15 +16,6 @@
|
||||
|
||||
package com.android.calendar.agenda;
|
||||
|
||||
import com.android.calendar.CalendarController;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.DeleteEventHelper;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.agenda.AgendaAdapter.ViewHolder;
|
||||
import com.android.calendar.agenda.AgendaWindowAdapter.DayAdapterInfo;
|
||||
import com.android.calendar.agenda.AgendaWindowAdapter.AgendaItem;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
@ -38,6 +29,16 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.CalendarController;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.DeleteEventHelper;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.agenda.AgendaAdapter.ViewHolder;
|
||||
import com.android.calendar.agenda.AgendaWindowAdapter.AgendaItem;
|
||||
import com.android.calendar.agenda.AgendaWindowAdapter.DayAdapterInfo;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AgendaListView extends ListView implements OnItemClickListener {
|
||||
|
||||
private static final String TAG = "AgendaListView";
|
||||
@ -49,9 +50,6 @@ public class AgendaListView extends ListView implements OnItemClickListener {
|
||||
private Context mContext;
|
||||
private String mTimeZone;
|
||||
private Time mTime;
|
||||
private boolean mShowEventDetailsWithAgenda;
|
||||
private Handler mHandler = null;
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -59,7 +57,8 @@ public class AgendaListView extends ListView implements OnItemClickListener {
|
||||
mTime.switchTimezone(mTimeZone);
|
||||
}
|
||||
};
|
||||
|
||||
private boolean mShowEventDetailsWithAgenda;
|
||||
private Handler mHandler = null;
|
||||
// runs every midnight and refreshes the view in order to update the past/present
|
||||
// separator
|
||||
private final Runnable mMidnightUpdater = new Runnable() {
|
||||
|
@ -44,7 +44,6 @@ import android.widget.TextView;
|
||||
import com.android.calendar.CalendarController;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.StickyHeaderListView;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
@ -55,6 +54,8 @@ import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/*
|
||||
Bugs Bugs Bugs:
|
||||
- At rotation and launch time, the initial position is not set properly. This code is calling
|
||||
@ -76,15 +77,6 @@ Check for leaks and excessive allocations
|
||||
public class AgendaWindowAdapter extends BaseAdapter
|
||||
implements StickyHeaderListView.HeaderIndexer, StickyHeaderListView.HeaderHeightListener{
|
||||
|
||||
static final boolean BASICLOG = false;
|
||||
static final boolean DEBUGLOG = false;
|
||||
private static final String TAG = "AgendaWindowAdapter";
|
||||
|
||||
private static final String AGENDA_SORT_ORDER =
|
||||
CalendarContract.Instances.START_DAY + " ASC, " +
|
||||
CalendarContract.Instances.BEGIN + " ASC, " +
|
||||
CalendarContract.Events.TITLE + " ASC";
|
||||
|
||||
public static final int INDEX_INSTANCE_ID = 0;
|
||||
public static final int INDEX_TITLE = 1;
|
||||
public static final int INDEX_EVENT_LOCATION = 2;
|
||||
@ -102,7 +94,13 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
public static final int INDEX_OWNER_ACCOUNT = 14;
|
||||
public static final int INDEX_CAN_ORGANIZER_RESPOND= 15;
|
||||
public static final int INDEX_TIME_ZONE = 16;
|
||||
|
||||
static final boolean BASICLOG = false;
|
||||
static final boolean DEBUGLOG = false;
|
||||
private static final String TAG = "AgendaWindowAdapter";
|
||||
private static final String AGENDA_SORT_ORDER =
|
||||
CalendarContract.Instances.START_DAY + " ASC, " +
|
||||
CalendarContract.Instances.BEGIN + " ASC, " +
|
||||
CalendarContract.Events.TITLE + " ASC";
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
Instances._ID, // 0
|
||||
Instances.TITLE, // 1
|
||||
@ -122,13 +120,6 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
Instances.CAN_ORGANIZER_RESPOND, // 15
|
||||
Instances.EVENT_TIMEZONE, // 16
|
||||
};
|
||||
|
||||
static {
|
||||
if (!Utils.isJellybeanOrLater()) {
|
||||
PROJECTION[INDEX_COLOR] = Instances.CALENDAR_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
// Listview may have a bug where the index/position is not consistent when there's a header.
|
||||
// position == positionInListView - OFF_BY_ONE_BUG
|
||||
// TODO Need to look into this.
|
||||
@ -138,73 +129,35 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
private static final int MIN_QUERY_DURATION = 7; // days
|
||||
private static final int MAX_QUERY_DURATION = 60; // days
|
||||
private static final int PREFETCH_BOUNDARY = 1;
|
||||
|
||||
/** Times to auto-expand/retry query after getting no data */
|
||||
private static final int RETRIES_ON_NO_DATA = 1;
|
||||
// Types of Query
|
||||
private static final int QUERY_TYPE_OLDER = 0; // Query for older events
|
||||
private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
|
||||
private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
|
||||
|
||||
static {
|
||||
if (!Utils.isJellybeanOrLater()) {
|
||||
PROJECTION[INDEX_COLOR] = Instances.CALENDAR_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
private final Resources mResources;
|
||||
private final QueryHandler mQueryHandler;
|
||||
private final AgendaListView mAgendaListView;
|
||||
|
||||
/** The sum of the rows in all the adapters */
|
||||
private int mRowCount;
|
||||
|
||||
/** The number of times we have queried and gotten no results back */
|
||||
private int mEmptyCursorCount;
|
||||
|
||||
/** Cached value of the last used adapter */
|
||||
private DayAdapterInfo mLastUsedInfo;
|
||||
|
||||
private final LinkedList<DayAdapterInfo> mAdapterInfos =
|
||||
new LinkedList<DayAdapterInfo>();
|
||||
private final ConcurrentLinkedQueue<QuerySpec> mQueryQueue =
|
||||
new ConcurrentLinkedQueue<QuerySpec>();
|
||||
private final TextView mHeaderView;
|
||||
private final TextView mFooterView;
|
||||
private boolean mDoneSettingUpHeaderFooter = false;
|
||||
|
||||
private final boolean mIsTabletConfig;
|
||||
|
||||
boolean mCleanQueryInitiated = false;
|
||||
private int mStickyHeaderSize = 44; // Initial size big enough for it to work
|
||||
|
||||
/**
|
||||
* When the user scrolled to the top, a query will be made for older events
|
||||
* and this will be incremented. Don't make more requests if
|
||||
* mOlderRequests > mOlderRequestsProcessed.
|
||||
*/
|
||||
private int mOlderRequests;
|
||||
|
||||
/** Number of "older" query that has been processed. */
|
||||
private int mOlderRequestsProcessed;
|
||||
|
||||
/**
|
||||
* When the user scrolled to the bottom, a query will be made for newer
|
||||
* events and this will be incremented. Don't make more requests if
|
||||
* mNewerRequests > mNewerRequestsProcessed.
|
||||
*/
|
||||
private int mNewerRequests;
|
||||
|
||||
/** Number of "newer" query that has been processed. */
|
||||
private int mNewerRequestsProcessed;
|
||||
|
||||
// Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
|
||||
private final Formatter mFormatter;
|
||||
private final StringBuilder mStringBuilder;
|
||||
private String mTimeZone;
|
||||
|
||||
// defines if to pop-up the current event when the agenda is first shown
|
||||
private final boolean mShowEventOnStart;
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTimeZone = Utils.getTimeZone(mContext, this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
|
||||
private final Handler mDataChangedHandler = new Handler();
|
||||
private final Runnable mDataChangedRunnable = new Runnable() {
|
||||
@Override
|
||||
@ -212,129 +165,56 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
|
||||
private boolean mShuttingDown;
|
||||
private boolean mHideDeclined;
|
||||
|
||||
// Used to stop a fling motion if the ListView is set to a specific position
|
||||
int mListViewScrollState = OnScrollListener.SCROLL_STATE_IDLE;
|
||||
|
||||
/** The current search query, or null if none */
|
||||
private String mSearchQuery;
|
||||
|
||||
private long mSelectedInstanceId = -1;
|
||||
|
||||
private final int mSelectedItemBackgroundColor;
|
||||
private final int mSelectedItemTextColor;
|
||||
private final float mItemRightMargin;
|
||||
|
||||
// Types of Query
|
||||
private static final int QUERY_TYPE_OLDER = 0; // Query for older events
|
||||
private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
|
||||
private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
|
||||
|
||||
private static class QuerySpec {
|
||||
long queryStartMillis;
|
||||
Time goToTime;
|
||||
int start;
|
||||
int end;
|
||||
String searchQuery;
|
||||
int queryType;
|
||||
long id;
|
||||
|
||||
public QuerySpec(int queryType) {
|
||||
this.queryType = queryType;
|
||||
id = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + end;
|
||||
result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
|
||||
result = prime * result + queryType;
|
||||
result = prime * result + start;
|
||||
if (searchQuery != null) {
|
||||
result = prime * result + searchQuery.hashCode();
|
||||
}
|
||||
if (goToTime != null) {
|
||||
long goToTimeMillis = goToTime.toMillis(false);
|
||||
result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
|
||||
}
|
||||
result = prime * result + (int)id;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
QuerySpec other = (QuerySpec) obj;
|
||||
if (end != other.end || queryStartMillis != other.queryStartMillis
|
||||
|| queryType != other.queryType || start != other.start
|
||||
|| Utils.equals(searchQuery, other.searchQuery) || id != other.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (goToTime != null) {
|
||||
if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (other.goToTime != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean mCleanQueryInitiated = false;
|
||||
// Used to stop a fling motion if the ListView is set to a specific position
|
||||
int mListViewScrollState = OnScrollListener.SCROLL_STATE_IDLE;
|
||||
/**
|
||||
* Class representing a list item within the Agenda view. Could be either an instance of an
|
||||
* event, or a header marking the specific day.
|
||||
*
|
||||
* The begin and end times of an AgendaItem should always be in local time, even if the event
|
||||
* is all day. buildAgendaItemFromCursor() converts each event to local time.
|
||||
* The sum of the rows in all the adapters
|
||||
*/
|
||||
static class AgendaItem {
|
||||
long begin;
|
||||
long end;
|
||||
long id;
|
||||
int startDay;
|
||||
boolean allDay;
|
||||
}
|
||||
|
||||
static class DayAdapterInfo {
|
||||
Cursor cursor;
|
||||
AgendaByDayAdapter dayAdapter;
|
||||
int start; // start day of the cursor's coverage
|
||||
int end; // end day of the cursor's coverage
|
||||
int offset; // offset in position in the list view
|
||||
int size; // dayAdapter.getCount()
|
||||
|
||||
public DayAdapterInfo(Context context) {
|
||||
dayAdapter = new AgendaByDayAdapter(context);
|
||||
}
|
||||
|
||||
private int mRowCount;
|
||||
/**
|
||||
* The number of times we have queried and gotten no results back
|
||||
*/
|
||||
private int mEmptyCursorCount;
|
||||
/**
|
||||
* Cached value of the last used adapter
|
||||
*/
|
||||
private DayAdapterInfo mLastUsedInfo;
|
||||
private boolean mDoneSettingUpHeaderFooter = false;
|
||||
private int mStickyHeaderSize = 44; // Initial size big enough for it to work
|
||||
/**
|
||||
* When the user scrolled to the top, a query will be made for older events
|
||||
* and this will be incremented. Don't make more requests if
|
||||
* mOlderRequests > mOlderRequestsProcessed.
|
||||
*/
|
||||
private int mOlderRequests;
|
||||
/** Number of "older" query that has been processed. */
|
||||
private int mOlderRequestsProcessed;
|
||||
/**
|
||||
* When the user scrolled to the bottom, a query will be made for newer
|
||||
* events and this will be incremented. Don't make more requests if
|
||||
* mNewerRequests > mNewerRequestsProcessed.
|
||||
*/
|
||||
private int mNewerRequests;
|
||||
/** Number of "newer" query that has been processed. */
|
||||
private int mNewerRequestsProcessed;
|
||||
private String mTimeZone;
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public String toString() {
|
||||
// Static class, so the time in this toString will not reflect the
|
||||
// home tz settings. This should only affect debugging.
|
||||
Time time = new Time();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
time.setJulianDay(start);
|
||||
time.normalize(false);
|
||||
sb.append("Start:").append(time.toString());
|
||||
time.setJulianDay(end);
|
||||
time.normalize(false);
|
||||
sb.append(" End:").append(time.toString());
|
||||
sb.append(" Offset:").append(offset);
|
||||
sb.append(" Size:").append(size);
|
||||
return sb.toString();
|
||||
public void run() {
|
||||
mTimeZone = Utils.getTimeZone(mContext, this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
private boolean mShuttingDown;
|
||||
private boolean mHideDeclined;
|
||||
/** The current search query, or null if none */
|
||||
private String mSearchQuery;
|
||||
private long mSelectedInstanceId = -1;
|
||||
private AgendaAdapter.ViewHolder mSelectedVH = null;
|
||||
|
||||
public AgendaWindowAdapter(Context context,
|
||||
AgendaListView agendaListView, boolean showEventOnStart) {
|
||||
@ -369,6 +249,25 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
mAgendaListView.addHeaderView(mHeaderView);
|
||||
}
|
||||
|
||||
static String getViewTitle(View x) {
|
||||
String title = "";
|
||||
if (x != null) {
|
||||
Object yy = x.getTag();
|
||||
if (yy instanceof AgendaAdapter.ViewHolder) {
|
||||
TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
|
||||
if (tv != null) {
|
||||
title = (String) tv.getText();
|
||||
}
|
||||
} else if (yy != null) {
|
||||
TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
|
||||
if (dateView != null) {
|
||||
title = (String) dateView.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
// Method in Adapter
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
@ -529,8 +428,6 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
return v;
|
||||
}
|
||||
|
||||
private AgendaAdapter.ViewHolder mSelectedVH = null;
|
||||
|
||||
private int findEventPositionNearestTime(Time time, long id) {
|
||||
DayAdapterInfo info = getAdapterInfoByTime(time);
|
||||
int pos = -1;
|
||||
@ -954,6 +851,221 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
formatDateString(end)));
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
mTZUpdater.run();
|
||||
}
|
||||
|
||||
public void setHideDeclinedEvents(boolean hideDeclined) {
|
||||
mHideDeclined = hideDeclined;
|
||||
}
|
||||
|
||||
public void setSelectedView(View v) {
|
||||
if (v != null) {
|
||||
Object vh = v.getTag();
|
||||
if (vh instanceof AgendaAdapter.ViewHolder) {
|
||||
mSelectedVH = (AgendaAdapter.ViewHolder) vh;
|
||||
if (mSelectedInstanceId != mSelectedVH.instanceId) {
|
||||
mSelectedInstanceId = mSelectedVH.instanceId;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AgendaAdapter.ViewHolder getSelectedViewHolder() {
|
||||
return mSelectedVH;
|
||||
}
|
||||
|
||||
public long getSelectedInstanceId() {
|
||||
return mSelectedInstanceId;
|
||||
}
|
||||
|
||||
public void setSelectedInstanceId(long selectedInstanceId) {
|
||||
mSelectedInstanceId = selectedInstanceId;
|
||||
mSelectedVH = null;
|
||||
}
|
||||
|
||||
private long findInstanceIdFromPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getInstanceId(position - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private long findStartTimeFromPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getStartTime(position - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Cursor getCursorByPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.cursor;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getCursorPositionByPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getCursorPosition(position - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the location of the day header of a specific event specified in the position
|
||||
// in the adapter
|
||||
@Override
|
||||
public int getHeaderPositionFromItemPosition(int position) {
|
||||
|
||||
// For phone configuration, return -1 so there will be no sticky header
|
||||
if (!mIsTabletConfig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
int pos = info.dayAdapter.getHeaderPosition(position - info.offset);
|
||||
return (pos != -1) ? (pos + info.offset) : -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the number of events for a specific day header
|
||||
@Override
|
||||
public int getHeaderItemsNumber(int headerPosition) {
|
||||
if (headerPosition < 0 || !mIsTabletConfig) {
|
||||
return -1;
|
||||
}
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(headerPosition);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getHeaderItemsCount(headerPosition - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void OnHeaderHeightChanged(int height) {
|
||||
mStickyHeaderSize = height;
|
||||
}
|
||||
|
||||
public int getStickyHeaderHeight() {
|
||||
return mStickyHeaderSize;
|
||||
}
|
||||
|
||||
// Implementation of HeaderIndexer interface for StickyHeeaderListView
|
||||
|
||||
public void setScrollState(int state) {
|
||||
mListViewScrollState = state;
|
||||
}
|
||||
|
||||
private static class QuerySpec {
|
||||
long queryStartMillis;
|
||||
Time goToTime;
|
||||
int start;
|
||||
int end;
|
||||
String searchQuery;
|
||||
int queryType;
|
||||
long id;
|
||||
|
||||
public QuerySpec(int queryType) {
|
||||
this.queryType = queryType;
|
||||
id = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + end;
|
||||
result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
|
||||
result = prime * result + queryType;
|
||||
result = prime * result + start;
|
||||
if (searchQuery != null) {
|
||||
result = prime * result + searchQuery.hashCode();
|
||||
}
|
||||
if (goToTime != null) {
|
||||
long goToTimeMillis = goToTime.toMillis(false);
|
||||
result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
|
||||
}
|
||||
result = prime * result + (int) id;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
QuerySpec other = (QuerySpec) obj;
|
||||
if (end != other.end || queryStartMillis != other.queryStartMillis
|
||||
|| queryType != other.queryType || start != other.start
|
||||
|| Utils.equals(searchQuery, other.searchQuery) || id != other.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (goToTime != null) {
|
||||
if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (other.goToTime != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a list item within the Agenda view. Could be either an instance of an
|
||||
* event, or a header marking the specific day.
|
||||
* <p/>
|
||||
* The begin and end times of an AgendaItem should always be in local time, even if the event
|
||||
* is all day. buildAgendaItemFromCursor() converts each event to local time.
|
||||
*/
|
||||
static class AgendaItem {
|
||||
long begin;
|
||||
long end;
|
||||
long id;
|
||||
int startDay;
|
||||
boolean allDay;
|
||||
}
|
||||
|
||||
static class DayAdapterInfo {
|
||||
Cursor cursor;
|
||||
AgendaByDayAdapter dayAdapter;
|
||||
int start; // start day of the cursor's coverage
|
||||
int end; // end day of the cursor's coverage
|
||||
int offset; // offset in position in the list view
|
||||
int size; // dayAdapter.getCount()
|
||||
|
||||
public DayAdapterInfo(Context context) {
|
||||
dayAdapter = new AgendaByDayAdapter(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// Static class, so the time in this toString will not reflect the
|
||||
// home tz settings. This should only affect debugging.
|
||||
Time time = new Time();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
time.setJulianDay(start);
|
||||
time.normalize(false);
|
||||
sb.append("Start:").append(time.toString());
|
||||
time.setJulianDay(end);
|
||||
time.normalize(false);
|
||||
sb.append(" End:").append(time.toString());
|
||||
sb.append(" Offset:").append(offset);
|
||||
sb.append(" Size:").append(size);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private class QueryHandler extends AsyncQueryHandler {
|
||||
|
||||
public QueryHandler(ContentResolver cr) {
|
||||
@ -1277,136 +1389,4 @@ public class AgendaWindowAdapter extends BaseAdapter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String getViewTitle(View x) {
|
||||
String title = "";
|
||||
if (x != null) {
|
||||
Object yy = x.getTag();
|
||||
if (yy instanceof AgendaAdapter.ViewHolder) {
|
||||
TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
|
||||
if (tv != null) {
|
||||
title = (String) tv.getText();
|
||||
}
|
||||
} else if (yy != null) {
|
||||
TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
|
||||
if (dateView != null) {
|
||||
title = (String) dateView.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
mTZUpdater.run();
|
||||
}
|
||||
|
||||
public void setHideDeclinedEvents(boolean hideDeclined) {
|
||||
mHideDeclined = hideDeclined;
|
||||
}
|
||||
|
||||
public void setSelectedView(View v) {
|
||||
if (v != null) {
|
||||
Object vh = v.getTag();
|
||||
if (vh instanceof AgendaAdapter.ViewHolder) {
|
||||
mSelectedVH = (AgendaAdapter.ViewHolder) vh;
|
||||
if (mSelectedInstanceId != mSelectedVH.instanceId) {
|
||||
mSelectedInstanceId = mSelectedVH.instanceId;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AgendaAdapter.ViewHolder getSelectedViewHolder() {
|
||||
return mSelectedVH;
|
||||
}
|
||||
|
||||
public long getSelectedInstanceId() {
|
||||
return mSelectedInstanceId;
|
||||
}
|
||||
|
||||
public void setSelectedInstanceId(long selectedInstanceId) {
|
||||
mSelectedInstanceId = selectedInstanceId;
|
||||
mSelectedVH = null;
|
||||
}
|
||||
|
||||
private long findInstanceIdFromPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getInstanceId(position - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private long findStartTimeFromPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getStartTime(position - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private Cursor getCursorByPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.cursor;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getCursorPositionByPosition(int position) {
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getCursorPosition(position - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Implementation of HeaderIndexer interface for StickyHeeaderListView
|
||||
|
||||
// Returns the location of the day header of a specific event specified in the position
|
||||
// in the adapter
|
||||
@Override
|
||||
public int getHeaderPositionFromItemPosition(int position) {
|
||||
|
||||
// For phone configuration, return -1 so there will be no sticky header
|
||||
if (!mIsTabletConfig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(position);
|
||||
if (info != null) {
|
||||
int pos = info.dayAdapter.getHeaderPosition(position - info.offset);
|
||||
return (pos != -1)?(pos + info.offset):-1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the number of events for a specific day header
|
||||
@Override
|
||||
public int getHeaderItemsNumber(int headerPosition) {
|
||||
if (headerPosition < 0 || !mIsTabletConfig) {
|
||||
return -1;
|
||||
}
|
||||
DayAdapterInfo info = getAdapterInfoByPosition(headerPosition);
|
||||
if (info != null) {
|
||||
return info.dayAdapter.getHeaderItemsCount(headerPosition - info.offset);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void OnHeaderHeightChanged(int height) {
|
||||
mStickyHeaderSize = height;
|
||||
}
|
||||
|
||||
public int getStickyHeaderHeight() {
|
||||
return mStickyHeaderSize;
|
||||
}
|
||||
|
||||
public void setScrollState(int state) {
|
||||
mListViewScrollState = state;
|
||||
}
|
||||
}
|
||||
|
@ -39,20 +39,32 @@ import android.widget.ListView;
|
||||
|
||||
import com.android.calendar.AsyncQueryService;
|
||||
import com.android.calendar.EventInfoActivity;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.alerts.GlobalDismissManager.AlarmId;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* The alert panel that pops up when there is a calendar event alarm.
|
||||
* This activity is started by an intent that specifies an event id.
|
||||
*/
|
||||
public class AlertActivity extends Activity implements OnClickListener {
|
||||
public static final int INDEX_ROW_ID = 0;
|
||||
public static final int INDEX_TITLE = 1;
|
||||
public static final int INDEX_EVENT_LOCATION = 2;
|
||||
public static final int INDEX_ALL_DAY = 3;
|
||||
public static final int INDEX_BEGIN = 4;
|
||||
public static final int INDEX_END = 5;
|
||||
public static final int INDEX_EVENT_ID = 6;
|
||||
public static final int INDEX_COLOR = 7;
|
||||
public static final int INDEX_RRULE = 8;
|
||||
public static final int INDEX_HAS_ALARM = 9;
|
||||
public static final int INDEX_STATE = 10;
|
||||
public static final int INDEX_ALARM_TIME = 11;
|
||||
private static final String TAG = "AlertActivity";
|
||||
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
CalendarAlerts._ID, // 0
|
||||
CalendarAlerts.TITLE, // 1
|
||||
@ -67,20 +79,6 @@ public class AlertActivity extends Activity implements OnClickListener {
|
||||
CalendarAlerts.STATE, // 10
|
||||
CalendarAlerts.ALARM_TIME, // 11
|
||||
};
|
||||
|
||||
public static final int INDEX_ROW_ID = 0;
|
||||
public static final int INDEX_TITLE = 1;
|
||||
public static final int INDEX_EVENT_LOCATION = 2;
|
||||
public static final int INDEX_ALL_DAY = 3;
|
||||
public static final int INDEX_BEGIN = 4;
|
||||
public static final int INDEX_END = 5;
|
||||
public static final int INDEX_EVENT_ID = 6;
|
||||
public static final int INDEX_COLOR = 7;
|
||||
public static final int INDEX_RRULE = 8;
|
||||
public static final int INDEX_HAS_ALARM = 9;
|
||||
public static final int INDEX_STATE = 10;
|
||||
public static final int INDEX_ALARM_TIME = 11;
|
||||
|
||||
private static final String SELECTION = CalendarAlerts.STATE + "=?";
|
||||
private static final String[] SELECTIONARG = new String[] {
|
||||
Integer.toString(CalendarAlerts.STATE_FIRED)
|
||||
@ -90,8 +88,39 @@ public class AlertActivity extends Activity implements OnClickListener {
|
||||
private QueryHandler mQueryHandler;
|
||||
private Cursor mCursor;
|
||||
private ListView mListView;
|
||||
private Button mDismissAllButton;
|
||||
private final OnItemClickListener mViewListener = new OnItemClickListener() {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position,
|
||||
long i) {
|
||||
AlertActivity alertActivity = AlertActivity.this;
|
||||
Cursor cursor = alertActivity.getItemForView(view);
|
||||
|
||||
long alarmId = cursor.getLong(INDEX_ROW_ID);
|
||||
long eventId = cursor.getLong(AlertActivity.INDEX_EVENT_ID);
|
||||
long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
|
||||
|
||||
// Mark this alarm as DISMISSED
|
||||
dismissAlarm(alarmId, eventId, startMillis);
|
||||
|
||||
// build an intent and task stack to start EventInfoActivity with AllInOneActivity
|
||||
// as the parent activity rooted to home.
|
||||
long endMillis = cursor.getLong(AlertActivity.INDEX_END);
|
||||
Intent eventIntent = AlertUtils.buildEventViewIntent(AlertActivity.this, eventId,
|
||||
startMillis, endMillis);
|
||||
|
||||
if (Utils.isJellybeanOrLater()) {
|
||||
TaskStackBuilder.create(AlertActivity.this).addParentStack(EventInfoActivity.class)
|
||||
.addNextIntent(eventIntent).startActivities();
|
||||
} else {
|
||||
alertActivity.startActivity(eventIntent);
|
||||
}
|
||||
|
||||
alertActivity.finish();
|
||||
}
|
||||
};
|
||||
private Button mDismissAllButton;
|
||||
|
||||
private void dismissFiredAlarms() {
|
||||
ContentValues values = new ContentValues(1 /* size */);
|
||||
@ -145,65 +174,6 @@ public class AlertActivity extends Activity implements OnClickListener {
|
||||
}.execute(alarmIds);
|
||||
}
|
||||
|
||||
private class QueryHandler extends AsyncQueryService {
|
||||
public QueryHandler(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
// Only set mCursor if the Activity is not finishing. Otherwise close the cursor.
|
||||
if (!isFinishing()) {
|
||||
mCursor = cursor;
|
||||
mAdapter.changeCursor(cursor);
|
||||
mListView.setSelection(cursor.getCount() - 1);
|
||||
|
||||
// The results are in, enable the buttons
|
||||
mDismissAllButton.setEnabled(true);
|
||||
} else {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdateComplete(int token, Object cookie, int result) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
private final OnItemClickListener mViewListener = new OnItemClickListener() {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position,
|
||||
long i) {
|
||||
AlertActivity alertActivity = AlertActivity.this;
|
||||
Cursor cursor = alertActivity.getItemForView(view);
|
||||
|
||||
long alarmId = cursor.getLong(INDEX_ROW_ID);
|
||||
long eventId = cursor.getLong(AlertActivity.INDEX_EVENT_ID);
|
||||
long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
|
||||
|
||||
// Mark this alarm as DISMISSED
|
||||
dismissAlarm(alarmId, eventId, startMillis);
|
||||
|
||||
// build an intent and task stack to start EventInfoActivity with AllInOneActivity
|
||||
// as the parent activity rooted to home.
|
||||
long endMillis = cursor.getLong(AlertActivity.INDEX_END);
|
||||
Intent eventIntent = AlertUtils.buildEventViewIntent(AlertActivity.this, eventId,
|
||||
startMillis, endMillis);
|
||||
|
||||
if (Utils.isJellybeanOrLater()) {
|
||||
TaskStackBuilder.create(AlertActivity.this).addParentStack(EventInfoActivity.class)
|
||||
.addNextIntent(eventIntent).startActivities();
|
||||
} else {
|
||||
alertActivity.startActivity(eventIntent);
|
||||
}
|
||||
|
||||
alertActivity.finish();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
@ -292,4 +262,30 @@ public class AlertActivity extends Activity implements OnClickListener {
|
||||
}
|
||||
return (Cursor) mListView.getAdapter().getItem(index);
|
||||
}
|
||||
|
||||
private class QueryHandler extends AsyncQueryService {
|
||||
public QueryHandler(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
// Only set mCursor if the Activity is not finishing. Otherwise close the cursor.
|
||||
if (!isFinishing()) {
|
||||
mCursor = cursor;
|
||||
mAdapter.changeCursor(cursor);
|
||||
mListView.setSelection(cursor.getCount() - 1);
|
||||
|
||||
// The results are in, enable the buttons
|
||||
mDismissAllButton.setEnabled(true);
|
||||
} else {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdateComplete(int token, Object cookie, int result) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.calendar.alerts;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
@ -30,9 +27,13 @@ import android.view.View;
|
||||
import android.widget.ResourceCursorAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AlertAdapter extends ResourceCursorAdapter {
|
||||
|
||||
private static AlertActivity alertActivity;
|
||||
@ -46,39 +47,6 @@ public class AlertAdapter extends ResourceCursorAdapter {
|
||||
alertActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
View square = view.findViewById(R.id.color_square);
|
||||
int color = Utils.getDisplayColorFromColor(cursor.getInt(AlertActivity.INDEX_COLOR));
|
||||
square.setBackgroundColor(color);
|
||||
|
||||
// Repeating info
|
||||
View repeatContainer = view.findViewById(R.id.repeat_icon);
|
||||
String rrule = cursor.getString(AlertActivity.INDEX_RRULE);
|
||||
if (!TextUtils.isEmpty(rrule)) {
|
||||
repeatContainer.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
repeatContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
/*
|
||||
// Reminder
|
||||
boolean hasAlarm = cursor.getInt(AlertActivity.INDEX_HAS_ALARM) != 0;
|
||||
if (hasAlarm) {
|
||||
AgendaAdapter.updateReminder(view, context, cursor.getLong(AlertActivity.INDEX_BEGIN),
|
||||
cursor.getLong(AlertActivity.INDEX_EVENT_ID));
|
||||
}
|
||||
*/
|
||||
|
||||
String eventName = cursor.getString(AlertActivity.INDEX_TITLE);
|
||||
String location = cursor.getString(AlertActivity.INDEX_EVENT_LOCATION);
|
||||
long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
|
||||
long endMillis = cursor.getLong(AlertActivity.INDEX_END);
|
||||
boolean allDay = cursor.getInt(AlertActivity.INDEX_ALL_DAY) != 0;
|
||||
|
||||
updateView(context, view, eventName, location, startMillis, endMillis, allDay);
|
||||
}
|
||||
|
||||
public static void updateView(Context context, View view, String eventName, String location,
|
||||
long startMillis, long endMillis, boolean allDay) {
|
||||
Resources res = context.getResources();
|
||||
@ -146,6 +114,39 @@ public class AlertAdapter extends ResourceCursorAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
View square = view.findViewById(R.id.color_square);
|
||||
int color = Utils.getDisplayColorFromColor(cursor.getInt(AlertActivity.INDEX_COLOR));
|
||||
square.setBackgroundColor(color);
|
||||
|
||||
// Repeating info
|
||||
View repeatContainer = view.findViewById(R.id.repeat_icon);
|
||||
String rrule = cursor.getString(AlertActivity.INDEX_RRULE);
|
||||
if (!TextUtils.isEmpty(rrule)) {
|
||||
repeatContainer.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
repeatContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
/*
|
||||
// Reminder
|
||||
boolean hasAlarm = cursor.getInt(AlertActivity.INDEX_HAS_ALARM) != 0;
|
||||
if (hasAlarm) {
|
||||
AgendaAdapter.updateReminder(view, context, cursor.getLong(AlertActivity.INDEX_BEGIN),
|
||||
cursor.getLong(AlertActivity.INDEX_EVENT_ID));
|
||||
}
|
||||
*/
|
||||
|
||||
String eventName = cursor.getString(AlertActivity.INDEX_TITLE);
|
||||
String location = cursor.getString(AlertActivity.INDEX_EVENT_LOCATION);
|
||||
long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
|
||||
long endMillis = cursor.getLong(AlertActivity.INDEX_END);
|
||||
boolean allDay = cursor.getInt(AlertActivity.INDEX_ALL_DAY) != 0;
|
||||
|
||||
updateView(context, view, eventName, location, startMillis, endMillis, allDay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onContentChanged () {
|
||||
super.onContentChanged();
|
||||
|
@ -43,7 +43,6 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.alerts.AlertService.NotificationWrapper;
|
||||
|
||||
@ -51,6 +50,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* Receives android.intent.action.EVENT_REMINDER intents and handles
|
||||
* event reminders. The intent URI specifies an alert id in the
|
||||
@ -66,113 +67,52 @@ import java.util.regex.Pattern;
|
||||
* -n "com.android.calendar/.alerts.AlertReceiver"
|
||||
*/
|
||||
public class AlertReceiver extends BroadcastReceiver {
|
||||
// The broadcast for notification refreshes scheduled by the app. This is to
|
||||
// distinguish the EVENT_REMINDER broadcast sent by the provider.
|
||||
public static final String EVENT_REMINDER_APP_ACTION =
|
||||
"com.android.calendar.EVENT_REMINDER_APP";
|
||||
public static final String ACTION_DISMISS_OLD_REMINDERS = "removeOldReminders";
|
||||
static final Object mStartingServiceSync = new Object();
|
||||
private static final String TAG = "AlertReceiver";
|
||||
|
||||
private static final String DELETE_ALL_ACTION = "com.android.calendar.DELETEALL";
|
||||
private static final String MAP_ACTION = "com.android.calendar.MAP";
|
||||
private static final String CALL_ACTION = "com.android.calendar.CALL";
|
||||
private static final String MAIL_ACTION = "com.android.calendar.MAIL";
|
||||
private static final String EXTRA_EVENT_ID = "eventid";
|
||||
|
||||
// The broadcast for notification refreshes scheduled by the app. This is to
|
||||
// distinguish the EVENT_REMINDER broadcast sent by the provider.
|
||||
public static final String EVENT_REMINDER_APP_ACTION =
|
||||
"com.android.calendar.EVENT_REMINDER_APP";
|
||||
|
||||
static final Object mStartingServiceSync = new Object();
|
||||
static PowerManager.WakeLock mStartingService;
|
||||
private static final Pattern mBlankLinePattern = Pattern.compile("^\\s*$[\n\r]",
|
||||
Pattern.MULTILINE);
|
||||
|
||||
public static final String ACTION_DISMISS_OLD_REMINDERS = "removeOldReminders";
|
||||
private static final int NOTIFICATION_DIGEST_MAX_LENGTH = 3;
|
||||
|
||||
private static final String GEO_PREFIX = "geo:";
|
||||
private static final String TEL_PREFIX = "tel:";
|
||||
private static final int MAX_NOTIF_ACTIONS = 3;
|
||||
|
||||
private static final String[] ATTENDEES_PROJECTION = new String[]{
|
||||
Attendees.ATTENDEE_EMAIL, // 0
|
||||
Attendees.ATTENDEE_STATUS, // 1
|
||||
};
|
||||
private static final int ATTENDEES_INDEX_EMAIL = 0;
|
||||
private static final int ATTENDEES_INDEX_STATUS = 1;
|
||||
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
|
||||
private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
|
||||
+ Attendees.ATTENDEE_EMAIL + " ASC";
|
||||
private static final String[] EVENT_PROJECTION = new String[]{
|
||||
Calendars.OWNER_ACCOUNT, // 0
|
||||
Calendars.ACCOUNT_NAME, // 1
|
||||
Events.TITLE, // 2
|
||||
Events.ORGANIZER, // 3
|
||||
};
|
||||
private static final int EVENT_INDEX_OWNER_ACCOUNT = 0;
|
||||
private static final int EVENT_INDEX_ACCOUNT_NAME = 1;
|
||||
private static final int EVENT_INDEX_TITLE = 2;
|
||||
private static final int EVENT_INDEX_ORGANIZER = 3;
|
||||
static PowerManager.WakeLock mStartingService;
|
||||
private static Handler sAsyncHandler;
|
||||
|
||||
static {
|
||||
HandlerThread thr = new HandlerThread("AlertReceiver async");
|
||||
thr.start();
|
||||
sAsyncHandler = new Handler(thr.getLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (AlertService.DEBUG) {
|
||||
Log.d(TAG, "onReceive: a=" + intent.getAction() + " " + intent.toString());
|
||||
}
|
||||
if (DELETE_ALL_ACTION.equals(intent.getAction())) {
|
||||
|
||||
// The user has dismissed a digest notification.
|
||||
// TODO Grab a wake lock here?
|
||||
Intent serviceIntent = new Intent(context, DismissAlarmsService.class);
|
||||
context.startService(serviceIntent);
|
||||
} else if (MAP_ACTION.equals(intent.getAction())) {
|
||||
// Try starting the map action.
|
||||
// If no map location is found (something changed since the notification was originally
|
||||
// fired), update the notifications to express this change.
|
||||
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
|
||||
if (eventId != -1) {
|
||||
URLSpan[] urlSpans = getURLSpans(context, eventId);
|
||||
Intent geoIntent = createMapActivityIntent(context, urlSpans);
|
||||
if (geoIntent != null) {
|
||||
// Location was successfully found, so dismiss the shade and start maps.
|
||||
context.startActivity(geoIntent);
|
||||
closeNotificationShade(context);
|
||||
} else {
|
||||
// No location was found, so update all notifications.
|
||||
// Our alert service does not currently allow us to specify only one
|
||||
// specific notification to refresh.
|
||||
AlertService.updateAlertNotification(context);
|
||||
}
|
||||
}
|
||||
} else if (CALL_ACTION.equals(intent.getAction())) {
|
||||
// Try starting the call action.
|
||||
// If no call location is found (something changed since the notification was originally
|
||||
// fired), update the notifications to express this change.
|
||||
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
|
||||
if (eventId != -1) {
|
||||
URLSpan[] urlSpans = getURLSpans(context, eventId);
|
||||
Intent callIntent = createCallActivityIntent(context, urlSpans);
|
||||
if (callIntent != null) {
|
||||
// Call location was successfully found, so dismiss the shade and start dialer.
|
||||
context.startActivity(callIntent);
|
||||
closeNotificationShade(context);
|
||||
} else {
|
||||
// No call location was found, so update all notifications.
|
||||
// Our alert service does not currently allow us to specify only one
|
||||
// specific notification to refresh.
|
||||
AlertService.updateAlertNotification(context);
|
||||
}
|
||||
}
|
||||
} else if (MAIL_ACTION.equals(intent.getAction())) {
|
||||
closeNotificationShade(context);
|
||||
|
||||
// Now start the email intent.
|
||||
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
|
||||
if (eventId != -1) {
|
||||
Intent i = new Intent(context, QuickResponseActivity.class);
|
||||
i.putExtra(QuickResponseActivity.EXTRA_EVENT_ID, eventId);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
}
|
||||
} else {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, AlertService.class);
|
||||
i.putExtras(intent);
|
||||
i.putExtra("action", intent.getAction());
|
||||
Uri uri = intent.getData();
|
||||
|
||||
// This intent might be a BOOT_COMPLETED so it might not have a Uri.
|
||||
if (uri != null) {
|
||||
i.putExtra("uri", uri.toString());
|
||||
}
|
||||
beginStartingService(context, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the service to process the current event notifications, acquiring
|
||||
* the wake lock before returning to ensure that the service will run.
|
||||
@ -595,32 +535,6 @@ public class AlertReceiver extends BroadcastReceiver {
|
||||
return nw;
|
||||
}
|
||||
|
||||
private void closeNotificationShade(Context context) {
|
||||
Intent closeNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
context.sendBroadcast(closeNotificationShadeIntent);
|
||||
}
|
||||
|
||||
private static final String[] ATTENDEES_PROJECTION = new String[] {
|
||||
Attendees.ATTENDEE_EMAIL, // 0
|
||||
Attendees.ATTENDEE_STATUS, // 1
|
||||
};
|
||||
private static final int ATTENDEES_INDEX_EMAIL = 0;
|
||||
private static final int ATTENDEES_INDEX_STATUS = 1;
|
||||
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
|
||||
private static final String ATTENDEES_SORT_ORDER = Attendees.ATTENDEE_NAME + " ASC, "
|
||||
+ Attendees.ATTENDEE_EMAIL + " ASC";
|
||||
|
||||
private static final String[] EVENT_PROJECTION = new String[] {
|
||||
Calendars.OWNER_ACCOUNT, // 0
|
||||
Calendars.ACCOUNT_NAME, // 1
|
||||
Events.TITLE, // 2
|
||||
Events.ORGANIZER, // 3
|
||||
};
|
||||
private static final int EVENT_INDEX_OWNER_ACCOUNT = 0;
|
||||
private static final int EVENT_INDEX_ACCOUNT_NAME = 1;
|
||||
private static final int EVENT_INDEX_TITLE = 2;
|
||||
private static final int EVENT_INDEX_ORGANIZER = 3;
|
||||
|
||||
private static Cursor getEventCursor(Context context, long eventId) {
|
||||
return context.getContentResolver().query(
|
||||
ContentUris.withAppendedId(Events.CONTENT_URI, eventId), EVENT_PROJECTION,
|
||||
@ -889,4 +803,84 @@ public class AlertReceiver extends BroadcastReceiver {
|
||||
// No tel link was found, so return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (AlertService.DEBUG) {
|
||||
Log.d(TAG, "onReceive: a=" + intent.getAction() + " " + intent.toString());
|
||||
}
|
||||
if (DELETE_ALL_ACTION.equals(intent.getAction())) {
|
||||
|
||||
// The user has dismissed a digest notification.
|
||||
// TODO Grab a wake lock here?
|
||||
Intent serviceIntent = new Intent(context, DismissAlarmsService.class);
|
||||
context.startService(serviceIntent);
|
||||
} else if (MAP_ACTION.equals(intent.getAction())) {
|
||||
// Try starting the map action.
|
||||
// If no map location is found (something changed since the notification was originally
|
||||
// fired), update the notifications to express this change.
|
||||
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
|
||||
if (eventId != -1) {
|
||||
URLSpan[] urlSpans = getURLSpans(context, eventId);
|
||||
Intent geoIntent = createMapActivityIntent(context, urlSpans);
|
||||
if (geoIntent != null) {
|
||||
// Location was successfully found, so dismiss the shade and start maps.
|
||||
context.startActivity(geoIntent);
|
||||
closeNotificationShade(context);
|
||||
} else {
|
||||
// No location was found, so update all notifications.
|
||||
// Our alert service does not currently allow us to specify only one
|
||||
// specific notification to refresh.
|
||||
AlertService.updateAlertNotification(context);
|
||||
}
|
||||
}
|
||||
} else if (CALL_ACTION.equals(intent.getAction())) {
|
||||
// Try starting the call action.
|
||||
// If no call location is found (something changed since the notification was originally
|
||||
// fired), update the notifications to express this change.
|
||||
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
|
||||
if (eventId != -1) {
|
||||
URLSpan[] urlSpans = getURLSpans(context, eventId);
|
||||
Intent callIntent = createCallActivityIntent(context, urlSpans);
|
||||
if (callIntent != null) {
|
||||
// Call location was successfully found, so dismiss the shade and start dialer.
|
||||
context.startActivity(callIntent);
|
||||
closeNotificationShade(context);
|
||||
} else {
|
||||
// No call location was found, so update all notifications.
|
||||
// Our alert service does not currently allow us to specify only one
|
||||
// specific notification to refresh.
|
||||
AlertService.updateAlertNotification(context);
|
||||
}
|
||||
}
|
||||
} else if (MAIL_ACTION.equals(intent.getAction())) {
|
||||
closeNotificationShade(context);
|
||||
|
||||
// Now start the email intent.
|
||||
final long eventId = intent.getLongExtra(EXTRA_EVENT_ID, -1);
|
||||
if (eventId != -1) {
|
||||
Intent i = new Intent(context, QuickResponseActivity.class);
|
||||
i.putExtra(QuickResponseActivity.EXTRA_EVENT_ID, eventId);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
}
|
||||
} else {
|
||||
Intent i = new Intent();
|
||||
i.setClass(context, AlertService.class);
|
||||
i.putExtras(intent);
|
||||
i.putExtra("action", intent.getAction());
|
||||
Uri uri = intent.getData();
|
||||
|
||||
// This intent might be a BOOT_COMPLETED so it might not have a Uri.
|
||||
if (uri != null) {
|
||||
i.putExtra("uri", uri.toString());
|
||||
}
|
||||
beginStartingService(context, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void closeNotificationShade(Context context) {
|
||||
Intent closeNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
context.sendBroadcast(closeNotificationShadeIntent);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ import android.util.Log;
|
||||
|
||||
import com.android.calendar.GeneralPreferences;
|
||||
import com.android.calendar.OtherPreferences;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -52,16 +51,15 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* This service is used to handle calendar event reminders.
|
||||
*/
|
||||
public class AlertService extends Service {
|
||||
// Hard limit to the number of notifications displayed.
|
||||
public static final int MAX_NOTIFICATIONS = 20;
|
||||
static final boolean DEBUG = true;
|
||||
private static final String TAG = "AlertService";
|
||||
|
||||
private volatile Looper mServiceLooper;
|
||||
private volatile ServiceHandler mServiceHandler;
|
||||
|
||||
static final String[] ALERT_PROJECTION = new String[] {
|
||||
CalendarAlerts._ID, // 0
|
||||
CalendarAlerts.EVENT_ID, // 1
|
||||
@ -76,7 +74,7 @@ public class AlertService extends Service {
|
||||
CalendarAlerts.END, // 10
|
||||
CalendarAlerts.DESCRIPTION, // 11
|
||||
};
|
||||
|
||||
private static final String TAG = "AlertService";
|
||||
private static final int ALERT_INDEX_ID = 0;
|
||||
private static final int ALERT_INDEX_EVENT_ID = 1;
|
||||
private static final int ALERT_INDEX_STATE = 2;
|
||||
@ -89,28 +87,18 @@ public class AlertService extends Service {
|
||||
private static final int ALERT_INDEX_BEGIN = 9;
|
||||
private static final int ALERT_INDEX_END = 10;
|
||||
private static final int ALERT_INDEX_DESCRIPTION = 11;
|
||||
|
||||
private static final String ACTIVE_ALERTS_SELECTION = "(" + CalendarAlerts.STATE + "=? OR "
|
||||
+ CalendarAlerts.STATE + "=?) AND " + CalendarAlerts.ALARM_TIME + "<=";
|
||||
|
||||
private static final String[] ACTIVE_ALERTS_SELECTION_ARGS = new String[] {
|
||||
Integer.toString(CalendarAlerts.STATE_FIRED),
|
||||
Integer.toString(CalendarAlerts.STATE_SCHEDULED)
|
||||
};
|
||||
|
||||
private static final String ACTIVE_ALERTS_SORT = "begin DESC, end DESC";
|
||||
|
||||
private static final String DISMISS_OLD_SELECTION = CalendarAlerts.END + "<? AND "
|
||||
+ CalendarAlerts.STATE + "=?";
|
||||
|
||||
private static final int MINUTE_MS = 60 * 1000;
|
||||
|
||||
// The grace period before changing a notification's priority bucket.
|
||||
private static final int MIN_DEPRIORITIZE_GRACE_PERIOD_MS = 15 * MINUTE_MS;
|
||||
|
||||
// Hard limit to the number of notifications displayed.
|
||||
public static final int MAX_NOTIFICATIONS = 20;
|
||||
|
||||
// Shared prefs key for storing whether the EVENT_REMINDER event from the provider
|
||||
// was ever received. Some OEMs modified this provider broadcast, so we had to
|
||||
// do the alarm scheduling here in the app, for the unbundled app's reminders to work.
|
||||
@ -118,132 +106,23 @@ public class AlertService extends Service {
|
||||
// alarm scheduling.
|
||||
private static final String PROVIDER_REMINDER_PREF_KEY =
|
||||
"preference_received_provider_reminder_broadcast";
|
||||
private static final String SORT_ORDER_ALARMTIME_ASC =
|
||||
CalendarContract.CalendarAlerts.ALARM_TIME + " ASC";
|
||||
private static final String WHERE_RESCHEDULE_MISSED_ALARMS =
|
||||
CalendarContract.CalendarAlerts.STATE
|
||||
+ "="
|
||||
+ CalendarContract.CalendarAlerts.STATE_SCHEDULED
|
||||
+ " AND "
|
||||
+ CalendarContract.CalendarAlerts.ALARM_TIME
|
||||
+ "<?"
|
||||
+ " AND "
|
||||
+ CalendarContract.CalendarAlerts.ALARM_TIME
|
||||
+ ">?"
|
||||
+ " AND "
|
||||
+ CalendarContract.CalendarAlerts.END + ">=?";
|
||||
private static Boolean sReceivedProviderReminderBroadcast = null;
|
||||
|
||||
// Added wrapper for testing
|
||||
public static class NotificationWrapper {
|
||||
Notification mNotification;
|
||||
long mEventId;
|
||||
long mBegin;
|
||||
long mEnd;
|
||||
ArrayList<NotificationWrapper> mNw;
|
||||
|
||||
public NotificationWrapper(Notification n, int notificationId, long eventId,
|
||||
long startMillis, long endMillis, boolean doPopup) {
|
||||
mNotification = n;
|
||||
mEventId = eventId;
|
||||
mBegin = startMillis;
|
||||
mEnd = endMillis;
|
||||
|
||||
// popup?
|
||||
// notification id?
|
||||
}
|
||||
|
||||
public NotificationWrapper(Notification n) {
|
||||
mNotification = n;
|
||||
}
|
||||
|
||||
public void add(NotificationWrapper nw) {
|
||||
if (mNw == null) {
|
||||
mNw = new ArrayList<NotificationWrapper>();
|
||||
}
|
||||
mNw.add(nw);
|
||||
}
|
||||
}
|
||||
|
||||
// Added wrapper for testing
|
||||
public static class NotificationMgrWrapper extends NotificationMgr {
|
||||
NotificationManager mNm;
|
||||
|
||||
public NotificationMgrWrapper(NotificationManager nm) {
|
||||
mNm = nm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(int id) {
|
||||
mNm.cancel(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(int id, NotificationWrapper nw) {
|
||||
mNm.notify(id, nw.mNotification);
|
||||
}
|
||||
}
|
||||
|
||||
void processMessage(Message msg) {
|
||||
Bundle bundle = (Bundle) msg.obj;
|
||||
|
||||
// On reboot, update the notification bar with the contents of the
|
||||
// CalendarAlerts table.
|
||||
String action = bundle.getString("action");
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, bundle.getLong(android.provider.CalendarContract.CalendarAlerts.ALARM_TIME)
|
||||
+ " Action = " + action);
|
||||
}
|
||||
|
||||
// Some OEMs had changed the provider's EVENT_REMINDER broadcast to their own event,
|
||||
// which broke our unbundled app's reminders. So we added backup alarm scheduling to the
|
||||
// app, but we know we can turn it off if we ever receive the EVENT_REMINDER broadcast.
|
||||
boolean providerReminder = action.equals(
|
||||
android.provider.CalendarContract.ACTION_EVENT_REMINDER);
|
||||
if (providerReminder) {
|
||||
if (sReceivedProviderReminderBroadcast == null) {
|
||||
sReceivedProviderReminderBroadcast = Utils.getSharedPreference(this,
|
||||
PROVIDER_REMINDER_PREF_KEY, false);
|
||||
}
|
||||
|
||||
if (!sReceivedProviderReminderBroadcast) {
|
||||
sReceivedProviderReminderBroadcast = true;
|
||||
Log.d(TAG, "Setting key " + PROVIDER_REMINDER_PREF_KEY + " to: true");
|
||||
Utils.setSharedPreference(this, PROVIDER_REMINDER_PREF_KEY, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (providerReminder ||
|
||||
action.equals(Intent.ACTION_PROVIDER_CHANGED) ||
|
||||
action.equals(android.provider.CalendarContract.ACTION_EVENT_REMINDER) ||
|
||||
action.equals(AlertReceiver.EVENT_REMINDER_APP_ACTION) ||
|
||||
action.equals(Intent.ACTION_LOCALE_CHANGED)) {
|
||||
|
||||
// b/7652098: Add a delay after the provider-changed event before refreshing
|
||||
// notifications to help issue with the unbundled app installed on HTC having
|
||||
// stale notifications.
|
||||
if (action.equals(Intent.ACTION_PROVIDER_CHANGED)) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
updateAlertNotification(this);
|
||||
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
// The provider usually initiates this setting up of alarms on startup,
|
||||
// but there was a bug (b/7221716) where a race condition caused this step to be
|
||||
// skipped, resulting in missed alarms. This is a stopgap to minimize this bug
|
||||
// for devices that don't have the provider fix, by initiating this a 2nd time here.
|
||||
// However, it would still theoretically be possible to hit the race condition
|
||||
// the 2nd time and still miss alarms.
|
||||
//
|
||||
// TODO: Remove this when the provider fix is rolled out everywhere.
|
||||
Intent intent = new Intent();
|
||||
intent.setClass(this, InitAlarmsService.class);
|
||||
startService(intent);
|
||||
} else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
|
||||
doTimeChanged();
|
||||
} else if (action.equals(AlertReceiver.ACTION_DISMISS_OLD_REMINDERS)) {
|
||||
dismissOldAlerts(this);
|
||||
} else {
|
||||
Log.w(TAG, "Invalid action: " + action);
|
||||
}
|
||||
|
||||
// Schedule the alarm for the next upcoming reminder, if not done by the provider.
|
||||
if (sReceivedProviderReminderBroadcast == null || !sReceivedProviderReminderBroadcast) {
|
||||
Log.d(TAG, "Scheduling next alarm with AlarmScheduler. "
|
||||
+ "sEventReminderReceived: " + sReceivedProviderReminderBroadcast);
|
||||
AlarmScheduler.scheduleNextAlarm(this);
|
||||
}
|
||||
}
|
||||
private volatile Looper mServiceLooper;
|
||||
private volatile ServiceHandler mServiceHandler;
|
||||
|
||||
static void dismissOldAlerts(Context context) {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
@ -895,29 +774,6 @@ public class AlertService extends Service {
|
||||
return tickerText;
|
||||
}
|
||||
|
||||
static class NotificationInfo {
|
||||
String eventName;
|
||||
String location;
|
||||
String description;
|
||||
long startMillis;
|
||||
long endMillis;
|
||||
long eventId;
|
||||
boolean allDay;
|
||||
boolean newAlert;
|
||||
|
||||
NotificationInfo(String eventName, String location, String description, long startMillis,
|
||||
long endMillis, long eventId, boolean allDay, boolean newAlert) {
|
||||
this.eventName = eventName;
|
||||
this.location = location;
|
||||
this.description = description;
|
||||
this.startMillis = startMillis;
|
||||
this.endMillis = endMillis;
|
||||
this.eventId = eventId;
|
||||
this.newAlert = newAlert;
|
||||
this.allDay = allDay;
|
||||
}
|
||||
}
|
||||
|
||||
private static void addNotificationOptions(NotificationWrapper nw, boolean quietUpdate,
|
||||
String tickerText, boolean defaultVibrate, String reminderRingtone,
|
||||
boolean showLights) {
|
||||
@ -950,79 +806,6 @@ public class AlertService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ static class NotificationPrefs {
|
||||
boolean quietUpdate;
|
||||
private Context context;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
// These are lazily initialized, do not access any of the following directly; use getters.
|
||||
private int doPopup = -1;
|
||||
private int defaultVibrate = -1;
|
||||
private String ringtone = null;
|
||||
|
||||
private static final String EMPTY_RINGTONE = "";
|
||||
|
||||
NotificationPrefs(Context context, SharedPreferences prefs, boolean quietUpdate) {
|
||||
this.context = context;
|
||||
this.prefs = prefs;
|
||||
this.quietUpdate = quietUpdate;
|
||||
}
|
||||
|
||||
private boolean getDoPopup() {
|
||||
if (doPopup < 0) {
|
||||
if (prefs.getBoolean(GeneralPreferences.KEY_ALERTS_POPUP, false)) {
|
||||
doPopup = 1;
|
||||
} else {
|
||||
doPopup = 0;
|
||||
}
|
||||
}
|
||||
return doPopup == 1;
|
||||
}
|
||||
|
||||
private boolean getDefaultVibrate() {
|
||||
if (defaultVibrate < 0) {
|
||||
defaultVibrate = Utils.getDefaultVibrate(context, prefs) ? 1 : 0;
|
||||
}
|
||||
return defaultVibrate == 1;
|
||||
}
|
||||
|
||||
private String getRingtoneAndSilence() {
|
||||
if (ringtone == null) {
|
||||
if (quietUpdate) {
|
||||
ringtone = EMPTY_RINGTONE;
|
||||
} else {
|
||||
ringtone = Utils.getRingTonePreference(context);
|
||||
}
|
||||
}
|
||||
String retVal = ringtone;
|
||||
ringtone = EMPTY_RINGTONE;
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
private void doTimeChanged() {
|
||||
ContentResolver cr = getContentResolver();
|
||||
// TODO Move this into Provider
|
||||
rescheduleMissedAlarms(cr, this, AlertUtils.createAlarmManager(this));
|
||||
updateAlertNotification(this);
|
||||
}
|
||||
|
||||
private static final String SORT_ORDER_ALARMTIME_ASC =
|
||||
CalendarContract.CalendarAlerts.ALARM_TIME + " ASC";
|
||||
|
||||
private static final String WHERE_RESCHEDULE_MISSED_ALARMS =
|
||||
CalendarContract.CalendarAlerts.STATE
|
||||
+ "="
|
||||
+ CalendarContract.CalendarAlerts.STATE_SCHEDULED
|
||||
+ " AND "
|
||||
+ CalendarContract.CalendarAlerts.ALARM_TIME
|
||||
+ "<?"
|
||||
+ " AND "
|
||||
+ CalendarContract.CalendarAlerts.ALARM_TIME
|
||||
+ ">?"
|
||||
+ " AND "
|
||||
+ CalendarContract.CalendarAlerts.END + ">=?";
|
||||
|
||||
/**
|
||||
* Searches the CalendarAlerts table for alarms that should have fired but
|
||||
* have not and then reschedules them. This method can be called at boot
|
||||
@ -1074,18 +857,86 @@ public class AlertService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private final class ServiceHandler extends Handler {
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper);
|
||||
void processMessage(Message msg) {
|
||||
Bundle bundle = (Bundle) msg.obj;
|
||||
|
||||
// On reboot, update the notification bar with the contents of the
|
||||
// CalendarAlerts table.
|
||||
String action = bundle.getString("action");
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, bundle.getLong(android.provider.CalendarContract.CalendarAlerts.ALARM_TIME)
|
||||
+ " Action = " + action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
processMessage(msg);
|
||||
// NOTE: We MUST not call stopSelf() directly, since we need to
|
||||
// make sure the wake lock acquired by AlertReceiver is released.
|
||||
AlertReceiver.finishStartingService(AlertService.this, msg.arg1);
|
||||
// Some OEMs had changed the provider's EVENT_REMINDER broadcast to their own event,
|
||||
// which broke our unbundled app's reminders. So we added backup alarm scheduling to the
|
||||
// app, but we know we can turn it off if we ever receive the EVENT_REMINDER broadcast.
|
||||
boolean providerReminder = action.equals(
|
||||
android.provider.CalendarContract.ACTION_EVENT_REMINDER);
|
||||
if (providerReminder) {
|
||||
if (sReceivedProviderReminderBroadcast == null) {
|
||||
sReceivedProviderReminderBroadcast = Utils.getSharedPreference(this,
|
||||
PROVIDER_REMINDER_PREF_KEY, false);
|
||||
}
|
||||
|
||||
if (!sReceivedProviderReminderBroadcast) {
|
||||
sReceivedProviderReminderBroadcast = true;
|
||||
Log.d(TAG, "Setting key " + PROVIDER_REMINDER_PREF_KEY + " to: true");
|
||||
Utils.setSharedPreference(this, PROVIDER_REMINDER_PREF_KEY, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (providerReminder ||
|
||||
action.equals(Intent.ACTION_PROVIDER_CHANGED) ||
|
||||
action.equals(android.provider.CalendarContract.ACTION_EVENT_REMINDER) ||
|
||||
action.equals(AlertReceiver.EVENT_REMINDER_APP_ACTION) ||
|
||||
action.equals(Intent.ACTION_LOCALE_CHANGED)) {
|
||||
|
||||
// b/7652098: Add a delay after the provider-changed event before refreshing
|
||||
// notifications to help issue with the unbundled app installed on HTC having
|
||||
// stale notifications.
|
||||
if (action.equals(Intent.ACTION_PROVIDER_CHANGED)) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
updateAlertNotification(this);
|
||||
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
// The provider usually initiates this setting up of alarms on startup,
|
||||
// but there was a bug (b/7221716) where a race condition caused this step to be
|
||||
// skipped, resulting in missed alarms. This is a stopgap to minimize this bug
|
||||
// for devices that don't have the provider fix, by initiating this a 2nd time here.
|
||||
// However, it would still theoretically be possible to hit the race condition
|
||||
// the 2nd time and still miss alarms.
|
||||
//
|
||||
// TODO: Remove this when the provider fix is rolled out everywhere.
|
||||
Intent intent = new Intent();
|
||||
intent.setClass(this, InitAlarmsService.class);
|
||||
startService(intent);
|
||||
} else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
|
||||
doTimeChanged();
|
||||
} else if (action.equals(AlertReceiver.ACTION_DISMISS_OLD_REMINDERS)) {
|
||||
dismissOldAlerts(this);
|
||||
} else {
|
||||
Log.w(TAG, "Invalid action: " + action);
|
||||
}
|
||||
|
||||
// Schedule the alarm for the next upcoming reminder, if not done by the provider.
|
||||
if (sReceivedProviderReminderBroadcast == null || !sReceivedProviderReminderBroadcast) {
|
||||
Log.d(TAG, "Scheduling next alarm with AlarmScheduler. "
|
||||
+ "sEventReminderReceived: " + sReceivedProviderReminderBroadcast);
|
||||
AlarmScheduler.scheduleNextAlarm(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void doTimeChanged() {
|
||||
ContentResolver cr = getContentResolver();
|
||||
// TODO Move this into Provider
|
||||
rescheduleMissedAlarms(cr, this, AlertUtils.createAlarmManager(this));
|
||||
updateAlertNotification(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1121,4 +972,139 @@ public class AlertService extends Service {
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Added wrapper for testing
|
||||
public static class NotificationWrapper {
|
||||
Notification mNotification;
|
||||
long mEventId;
|
||||
long mBegin;
|
||||
long mEnd;
|
||||
ArrayList<NotificationWrapper> mNw;
|
||||
|
||||
public NotificationWrapper(Notification n, int notificationId, long eventId,
|
||||
long startMillis, long endMillis, boolean doPopup) {
|
||||
mNotification = n;
|
||||
mEventId = eventId;
|
||||
mBegin = startMillis;
|
||||
mEnd = endMillis;
|
||||
|
||||
// popup?
|
||||
// notification id?
|
||||
}
|
||||
|
||||
public NotificationWrapper(Notification n) {
|
||||
mNotification = n;
|
||||
}
|
||||
|
||||
public void add(NotificationWrapper nw) {
|
||||
if (mNw == null) {
|
||||
mNw = new ArrayList<NotificationWrapper>();
|
||||
}
|
||||
mNw.add(nw);
|
||||
}
|
||||
}
|
||||
|
||||
// Added wrapper for testing
|
||||
public static class NotificationMgrWrapper extends NotificationMgr {
|
||||
NotificationManager mNm;
|
||||
|
||||
public NotificationMgrWrapper(NotificationManager nm) {
|
||||
mNm = nm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(int id) {
|
||||
mNm.cancel(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(int id, NotificationWrapper nw) {
|
||||
mNm.notify(id, nw.mNotification);
|
||||
}
|
||||
}
|
||||
|
||||
static class NotificationInfo {
|
||||
String eventName;
|
||||
String location;
|
||||
String description;
|
||||
long startMillis;
|
||||
long endMillis;
|
||||
long eventId;
|
||||
boolean allDay;
|
||||
boolean newAlert;
|
||||
|
||||
NotificationInfo(String eventName, String location, String description, long startMillis,
|
||||
long endMillis, long eventId, boolean allDay, boolean newAlert) {
|
||||
this.eventName = eventName;
|
||||
this.location = location;
|
||||
this.description = description;
|
||||
this.startMillis = startMillis;
|
||||
this.endMillis = endMillis;
|
||||
this.eventId = eventId;
|
||||
this.newAlert = newAlert;
|
||||
this.allDay = allDay;
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ static class NotificationPrefs {
|
||||
private static final String EMPTY_RINGTONE = "";
|
||||
boolean quietUpdate;
|
||||
private Context context;
|
||||
private SharedPreferences prefs;
|
||||
// These are lazily initialized, do not access any of the following directly; use getters.
|
||||
private int doPopup = -1;
|
||||
private int defaultVibrate = -1;
|
||||
private String ringtone = null;
|
||||
|
||||
NotificationPrefs(Context context, SharedPreferences prefs, boolean quietUpdate) {
|
||||
this.context = context;
|
||||
this.prefs = prefs;
|
||||
this.quietUpdate = quietUpdate;
|
||||
}
|
||||
|
||||
private boolean getDoPopup() {
|
||||
if (doPopup < 0) {
|
||||
if (prefs.getBoolean(GeneralPreferences.KEY_ALERTS_POPUP, false)) {
|
||||
doPopup = 1;
|
||||
} else {
|
||||
doPopup = 0;
|
||||
}
|
||||
}
|
||||
return doPopup == 1;
|
||||
}
|
||||
|
||||
private boolean getDefaultVibrate() {
|
||||
if (defaultVibrate < 0) {
|
||||
defaultVibrate = Utils.getDefaultVibrate(context, prefs) ? 1 : 0;
|
||||
}
|
||||
return defaultVibrate == 1;
|
||||
}
|
||||
|
||||
private String getRingtoneAndSilence() {
|
||||
if (ringtone == null) {
|
||||
if (quietUpdate) {
|
||||
ringtone = EMPTY_RINGTONE;
|
||||
} else {
|
||||
ringtone = Utils.getRingTonePreference(context);
|
||||
}
|
||||
}
|
||||
String retVal = ringtone;
|
||||
ringtone = EMPTY_RINGTONE;
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ServiceHandler extends Handler {
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
processMessage(msg);
|
||||
// NOTE: We MUST not call stopSelf() directly, since we need to
|
||||
// make sure the wake lock acquired by AlertReceiver is released.
|
||||
AlertReceiver.finishStartingService(AlertService.this, msg.arg1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,21 +33,18 @@ import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.calendar.EventInfoActivity;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class AlertUtils {
|
||||
private static final String TAG = "AlertUtils";
|
||||
static final boolean DEBUG = true;
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AlertUtils {
|
||||
// We use one notification id for the expired events notification. All
|
||||
// other notifications (the 'active' future/concurrent ones) use a unique ID.
|
||||
public static final int EXPIRED_GROUP_NOTIFICATION_ID = 0;
|
||||
|
||||
public static final String EVENT_ID_KEY = "eventid";
|
||||
public static final String SHOW_EVENT_KEY = "showevent";
|
||||
public static final String EVENT_START_KEY = "eventstart";
|
||||
@ -56,28 +53,25 @@ public class AlertUtils {
|
||||
public static final String EVENT_IDS_KEY = "eventids";
|
||||
public static final String SNOOZE_DELAY_KEY = "snoozedelay";
|
||||
public static final String EVENT_STARTS_KEY = "starts";
|
||||
|
||||
// A flag for using local storage to save alert state instead of the alerts DB table.
|
||||
// This allows the unbundled app to run alongside other calendar apps without eating
|
||||
// alerts from other apps.
|
||||
static boolean BYPASS_DB = true;
|
||||
|
||||
static final boolean DEBUG = true;
|
||||
private static final String TAG = "AlertUtils";
|
||||
// SharedPrefs table name for storing fired alerts. This prevents other installed
|
||||
// Calendar apps from eating the alerts.
|
||||
private static final String ALERTS_SHARED_PREFS_NAME = "calendar_alerts";
|
||||
|
||||
// Keyname prefix for the alerts data in SharedPrefs. The key will contain a combo
|
||||
// of event ID, begin time, and alarm time. The value will be the fired time.
|
||||
private static final String KEY_FIRED_ALERT_PREFIX = "preference_alert_";
|
||||
|
||||
// The last time the SharedPrefs was scanned and flushed of old alerts data.
|
||||
private static final String KEY_LAST_FLUSH_TIME_MS = "preference_flushTimeMs";
|
||||
|
||||
// The # of days to save alert states in the shared prefs table, before flushing. This
|
||||
// can be any value, since AlertService will also check for a recent alertTime before
|
||||
// ringing the alert.
|
||||
private static final int FLUSH_INTERVAL_DAYS = 1;
|
||||
private static final int FLUSH_INTERVAL_MS = FLUSH_INTERVAL_DAYS * 24 * 60 * 60 * 1000;
|
||||
// A flag for using local storage to save alert state instead of the alerts DB table.
|
||||
// This allows the unbundled app to run alongside other calendar apps without eating
|
||||
// alerts from other apps.
|
||||
static boolean BYPASS_DB = true;
|
||||
|
||||
/**
|
||||
* Creates an AlarmManagerInterface that wraps a real AlarmManager. The alarm code
|
||||
|
@ -34,7 +34,6 @@ import android.util.Pair;
|
||||
|
||||
import com.android.calendar.CloudNotificationBackplane;
|
||||
import com.android.calendar.ExtensionsFactory;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
@ -44,16 +43,18 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* Utilities for managing notification dismissal across devices.
|
||||
*/
|
||||
public class GlobalDismissManager extends BroadcastReceiver {
|
||||
private static final String TAG = "GlobalDismissManager";
|
||||
private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
|
||||
private static final String GLOBAL_DISMISS_MANAGER_PREFS = "com.android.calendar.alerts.GDM";
|
||||
private static final String ACCOUNT_KEY = "known_accounts";
|
||||
public static final String KEY_PREFIX = "com.android.calendar.alerts.";
|
||||
public static final String SYNC_ID = KEY_PREFIX + "sync_id";
|
||||
public static final String START_TIME = KEY_PREFIX + "start_time";
|
||||
public static final String ACCOUNT_NAME = KEY_PREFIX + "account_name";
|
||||
public static final String DISMISS_INTENT = KEY_PREFIX + "DISMISS";
|
||||
protected static final long FOUR_WEEKS = 60 * 60 * 24 * 7 * 4;
|
||||
|
||||
static final String[] EVENT_PROJECTION = new String[] {
|
||||
Events._ID,
|
||||
Events.CALENDAR_ID
|
||||
@ -67,26 +68,15 @@ public class GlobalDismissManager extends BroadcastReceiver {
|
||||
Calendars.ACCOUNT_NAME,
|
||||
Calendars.ACCOUNT_TYPE
|
||||
};
|
||||
|
||||
public static final String KEY_PREFIX = "com.android.calendar.alerts.";
|
||||
public static final String SYNC_ID = KEY_PREFIX + "sync_id";
|
||||
public static final String START_TIME = KEY_PREFIX + "start_time";
|
||||
public static final String ACCOUNT_NAME = KEY_PREFIX + "account_name";
|
||||
public static final String DISMISS_INTENT = KEY_PREFIX + "DISMISS";
|
||||
|
||||
public static class AlarmId {
|
||||
public long mEventId;
|
||||
public long mStart;
|
||||
public AlarmId(long id, long start) {
|
||||
mEventId = id;
|
||||
mStart = start;
|
||||
}
|
||||
}
|
||||
private static final String TAG = "GlobalDismissManager";
|
||||
private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
|
||||
private static final String GLOBAL_DISMISS_MANAGER_PREFS = "com.android.calendar.alerts.GDM";
|
||||
private static final String ACCOUNT_KEY = "known_accounts";
|
||||
|
||||
/**
|
||||
* Look for unknown accounts in a set of events and associate with them.
|
||||
* Returns immediately, processing happens in the background.
|
||||
*
|
||||
*
|
||||
* @param context application context
|
||||
* @param eventIds IDs for events that have posted notifications that may be
|
||||
* dismissed.
|
||||
@ -156,7 +146,7 @@ public class GlobalDismissManager extends BroadcastReceiver {
|
||||
|
||||
/**
|
||||
* Globally dismiss notifications that are backed by the same events.
|
||||
*
|
||||
*
|
||||
* @param context application context
|
||||
* @param alarmIds Unique identifiers for events that have been dismissed by the user.
|
||||
* @return true if notification_sender_id is available
|
||||
@ -254,7 +244,7 @@ public class GlobalDismissManager extends BroadcastReceiver {
|
||||
|
||||
/**
|
||||
* build a selection over a set of row IDs
|
||||
*
|
||||
*
|
||||
* @param ids row IDs to select
|
||||
* @param key row name for the table
|
||||
* @return a selection string suitable for a resolver query.
|
||||
@ -382,4 +372,14 @@ public class GlobalDismissManager extends BroadcastReceiver {
|
||||
}
|
||||
}.execute(new Pair<Context, Intent>(context, intent));
|
||||
}
|
||||
|
||||
public static class AlarmId {
|
||||
public long mEventId;
|
||||
public long mStart;
|
||||
|
||||
public AlarmId(long id, long start) {
|
||||
mEventId = id;
|
||||
mStart = start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,11 +26,12 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* Activity which displays when the user wants to email guests from notifications.
|
||||
*
|
||||
@ -39,11 +40,10 @@ import java.util.Arrays;
|
||||
*
|
||||
*/
|
||||
public class QuickResponseActivity extends ListActivity implements OnItemClickListener {
|
||||
private static final String TAG = "QuickResponseActivity";
|
||||
public static final String EXTRA_EVENT_ID = "eventId";
|
||||
|
||||
private String[] mResponses = null;
|
||||
private static final String TAG = "QuickResponseActivity";
|
||||
static long mEventId;
|
||||
private String[] mResponses = null;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
|
@ -23,9 +23,10 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SnoozeDelayActivity extends Activity implements
|
||||
TimePickerDialog.OnTimeSetListener, DialogInterface.OnCancelListener {
|
||||
private static final int DIALOG_DELAY = 1;
|
||||
|
@ -16,44 +16,45 @@
|
||||
|
||||
package com.android.calendar.event;
|
||||
|
||||
import com.android.calendar.CalendarEventModel.Attendee;
|
||||
import com.android.calendar.ContactsAsyncHelper;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.event.EditEventHelper.AttendeeItem;
|
||||
import com.android.common.Rfc822Validator;
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.provider.CalendarContract.Attendees;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Identity;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Rfc822Token;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.QuickContactBadge;
|
||||
import android.widget.TextView;
|
||||
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.provider.CalendarContract.Attendees;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Identity;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Rfc822Token;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.QuickContactBadge;
|
||||
import android.widget.TextView;
|
||||
import com.android.calendar.CalendarEventModel.Attendee;
|
||||
import com.android.calendar.ContactsAsyncHelper;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.event.EditEventHelper.AttendeeItem;
|
||||
import com.android.common.Rfc822Validator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class AttendeesView extends LinearLayout implements View.OnClickListener {
|
||||
private static final String TAG = "AttendeesView";
|
||||
@ -88,17 +89,15 @@ public class AttendeesView extends LinearLayout implements View.OnClickListener
|
||||
private final View mDividerForNoResponse;
|
||||
private final int mNoResponsePhotoAlpha;
|
||||
private final int mDefaultPhotoAlpha;
|
||||
// Cache for loaded photos
|
||||
HashMap<String, Drawable> mRecycledPhotos;
|
||||
private Rfc822Validator mValidator;
|
||||
|
||||
// Number of attendees responding or not responding.
|
||||
private int mYes;
|
||||
private int mNo;
|
||||
private int mMaybe;
|
||||
private int mNoResponse;
|
||||
|
||||
// Cache for loaded photos
|
||||
HashMap<String, Drawable> mRecycledPhotos;
|
||||
|
||||
public AttendeesView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
@ -408,6 +407,22 @@ public class AttendeesView extends LinearLayout implements View.OnClickListener
|
||||
return ((AttendeeItem) view.getTag()).mRemoved;
|
||||
}
|
||||
|
||||
public Attendee getItem(int index) {
|
||||
final View view = getChildAt(index);
|
||||
if (view instanceof TextView) { // divider
|
||||
return null;
|
||||
}
|
||||
return ((AttendeeItem) view.getTag()).mAttendee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// Button corresponding to R.id.contact_remove.
|
||||
final AttendeeItem item = (AttendeeItem) view.getTag();
|
||||
item.mRemoved = !item.mRemoved;
|
||||
updateAttendeeView(item);
|
||||
}
|
||||
|
||||
// TODO put this into a Loader for auto-requeries
|
||||
private class PresenceQueryHandler extends AsyncQueryHandler {
|
||||
public PresenceQueryHandler(ContentResolver cr) {
|
||||
@ -467,20 +482,4 @@ public class AttendeesView extends LinearLayout implements View.OnClickListener
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Attendee getItem(int index) {
|
||||
final View view = getChildAt(index);
|
||||
if (view instanceof TextView) { // divider
|
||||
return null;
|
||||
}
|
||||
return ((AttendeeItem) view.getTag()).mAttendee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// Button corresponding to R.id.contact_remove.
|
||||
final AttendeeItem item = (AttendeeItem) view.getTag();
|
||||
item.mRemoved = !item.mRemoved;
|
||||
updateAttendeeView(item);
|
||||
}
|
||||
}
|
||||
|
@ -44,9 +44,10 @@ import com.android.calendar.CalendarController;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.CalendarEventModel;
|
||||
import com.android.calendar.GeneralPreferences;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
|
||||
/**
|
||||
* Allows the user to quickly create a new all-day event from the calendar's month view.
|
||||
@ -83,24 +84,6 @@ public class CreateEventDialogFragment extends DialogFragment implements TextWat
|
||||
private long mCalendarId = -1;
|
||||
private String mCalendarOwner;
|
||||
|
||||
private class CalendarQueryService extends AsyncQueryService {
|
||||
|
||||
/**
|
||||
* @param context
|
||||
*/
|
||||
public CalendarQueryService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
setDefaultCalendarView(cursor);
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CreateEventDialogFragment() {
|
||||
// Empty constructor required for DialogFragment.
|
||||
}
|
||||
@ -322,4 +305,22 @@ public class CreateEventDialogFragment extends DialogFragment implements TextWat
|
||||
mAccountName.setText(accountName);
|
||||
}
|
||||
}
|
||||
|
||||
private class CalendarQueryService extends AsyncQueryService {
|
||||
|
||||
/**
|
||||
* @param context
|
||||
*/
|
||||
public CalendarQueryService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
setDefaultCalendarView(cursor);
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ import com.android.calendar.CalendarController.EventInfo;
|
||||
import com.android.calendar.CalendarEventModel.ReminderEntry;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
@ -66,12 +66,12 @@ import com.android.calendar.Utils;
|
||||
import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
|
||||
import com.android.colorpicker.HsvColorComparator;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class EditEventFragment extends Fragment implements EventHandler, OnColorSelectedListener {
|
||||
private static final String TAG = "EditEventActivity";
|
||||
private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog";
|
||||
|
@ -74,7 +74,6 @@ import com.android.calendar.EmailAddressAdapter;
|
||||
import com.android.calendar.EventInfoFragment;
|
||||
import com.android.calendar.EventRecurrenceFormatter;
|
||||
import com.android.calendar.GeneralPreferences;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.RecipientAdapter;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.event.EditEventHelper.EditDoneRunnable;
|
||||
@ -102,6 +101,8 @@ import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class EditEventView implements View.OnClickListener, DialogInterface.OnCancelListener,
|
||||
DialogInterface.OnClickListener, OnItemSelectedListener,
|
||||
RecurrencePickerDialog.OnRecurrenceSetListener,
|
||||
@ -115,7 +116,18 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
private static final String FRAG_TAG_TIME_PICKER = "timePickerDialogFragment";
|
||||
private static final String FRAG_TAG_TIME_ZONE_PICKER = "timeZonePickerDialogFragment";
|
||||
private static final String FRAG_TAG_RECUR_PICKER = "recurrencePickerDialogFragment";
|
||||
|
||||
private static StringBuilder mSB = new StringBuilder(50);
|
||||
private static Formatter mF = new Formatter(mSB, Locale.getDefault());
|
||||
/**
|
||||
* From com.google.android.gm.ComposeActivity Implements special address
|
||||
* cleanup rules: The first space key entry following an "@" symbol that is
|
||||
* followed by any combination of letters and symbols, including one+ dots
|
||||
* and zero commas, should insert an extra comma (followed by the space).
|
||||
*/
|
||||
private static InputFilter[] sRecipientFilters = new InputFilter[]{new Rfc822InputFilter()};
|
||||
public boolean mIsMultipane;
|
||||
public boolean mTimeSelectedWasStartTime;
|
||||
public boolean mDateSelectedWasStartDate;
|
||||
ArrayList<View> mEditOnlyList = new ArrayList<View>();
|
||||
ArrayList<View> mEditViewList = new ArrayList<View>();
|
||||
ArrayList<View> mViewOnlyList = new ArrayList<View>();
|
||||
@ -160,10 +172,7 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
View mAttendeesGroup;
|
||||
View mStartHomeGroup;
|
||||
View mEndHomeGroup;
|
||||
|
||||
private int[] mOriginalPadding = new int[4];
|
||||
|
||||
public boolean mIsMultipane;
|
||||
private ProgressDialog mLoadingCalendarsDialog;
|
||||
private AlertDialog mNoCalendarsDialog;
|
||||
private DialogFragment mTimezoneDialog;
|
||||
@ -174,20 +183,15 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
private Cursor mCalendarsCursor;
|
||||
private AccountSpecifier mAddressAdapter;
|
||||
private Rfc822Validator mEmailValidator;
|
||||
|
||||
public boolean mTimeSelectedWasStartTime;
|
||||
public boolean mDateSelectedWasStartDate;
|
||||
private TimePickerDialog mStartTimePickerDialog;
|
||||
private TimePickerDialog mEndTimePickerDialog;
|
||||
private DatePickerDialog mDatePickerDialog;
|
||||
|
||||
/**
|
||||
* Contents of the "minutes" spinner. This has default values from the XML file, augmented
|
||||
* with any additional values that were already associated with the event.
|
||||
*/
|
||||
private ArrayList<Integer> mReminderMinuteValues;
|
||||
private ArrayList<String> mReminderMinuteLabels;
|
||||
|
||||
/**
|
||||
* Contents of the "methods" spinner. The "values" list specifies the method constant
|
||||
* (e.g. {@link Reminders#METHOD_ALERT}) associated with the labels. Any methods that
|
||||
@ -195,7 +199,6 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
*/
|
||||
private ArrayList<Integer> mReminderMethodValues;
|
||||
private ArrayList<String> mReminderMethodLabels;
|
||||
|
||||
/**
|
||||
* Contents of the "availability" spinner. The "values" list specifies the
|
||||
* type constant (e.g. {@link Events#AVAILABILITY_BUSY}) associated with the
|
||||
@ -208,189 +211,216 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
private boolean mAvailabilityExplicitlySet;
|
||||
private boolean mAllDayChangingAvailability;
|
||||
private int mAvailabilityCurrentlySelected;
|
||||
|
||||
private int mDefaultReminderMinutes;
|
||||
|
||||
private boolean mSaveAfterQueryComplete = false;
|
||||
|
||||
private TimeZonePickerUtils mTzPickerUtils;
|
||||
private Time mStartTime;
|
||||
private Time mEndTime;
|
||||
private String mTimezone;
|
||||
private boolean mAllDay = false;
|
||||
private int mModification = EditEventHelper.MODIFY_UNINITIALIZED;
|
||||
|
||||
private EventRecurrence mEventRecurrence = new EventRecurrence();
|
||||
|
||||
private ArrayList<LinearLayout> mReminderItems = new ArrayList<LinearLayout>(0);
|
||||
private ArrayList<ReminderEntry> mUnsupportedReminders = new ArrayList<ReminderEntry>();
|
||||
private String mRrule;
|
||||
|
||||
private static StringBuilder mSB = new StringBuilder(50);
|
||||
private static Formatter mF = new Formatter(mSB, Locale.getDefault());
|
||||
public EditEventView(Activity activity, View view, EditDoneRunnable done,
|
||||
boolean timeSelectedWasStartTime, boolean dateSelectedWasStartDate) {
|
||||
|
||||
/* This class is used to update the time buttons. */
|
||||
private class TimeListener implements OnTimeSetListener {
|
||||
private View mView;
|
||||
mActivity = activity;
|
||||
mView = view;
|
||||
mDone = done;
|
||||
|
||||
public TimeListener(View view) {
|
||||
mView = view;
|
||||
}
|
||||
// cache top level view elements
|
||||
mLoadingMessage = (TextView) view.findViewById(R.id.loading_message);
|
||||
mScrollView = (ScrollView) view.findViewById(R.id.scroll_view);
|
||||
|
||||
@Override
|
||||
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
|
||||
// Cache the member variables locally to avoid inner class overhead.
|
||||
Time startTime = mStartTime;
|
||||
Time endTime = mEndTime;
|
||||
// cache all the widgets
|
||||
mCalendarsSpinner = (Spinner) view.findViewById(R.id.calendars_spinner);
|
||||
mTitleTextView = (TextView) view.findViewById(R.id.title);
|
||||
mLocationTextView = (AutoCompleteTextView) view.findViewById(R.id.location);
|
||||
mDescriptionTextView = (TextView) view.findViewById(R.id.description);
|
||||
mTimezoneLabel = (TextView) view.findViewById(R.id.timezone_label);
|
||||
mStartDateButton = (Button) view.findViewById(R.id.start_date);
|
||||
mEndDateButton = (Button) view.findViewById(R.id.end_date);
|
||||
mWhenView = (TextView) mView.findViewById(R.id.when);
|
||||
mTimezoneTextView = (TextView) mView.findViewById(R.id.timezone_textView);
|
||||
mStartTimeButton = (Button) view.findViewById(R.id.start_time);
|
||||
mEndTimeButton = (Button) view.findViewById(R.id.end_time);
|
||||
mTimezoneButton = (Button) view.findViewById(R.id.timezone_button);
|
||||
mTimezoneButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showTimezoneDialog();
|
||||
}
|
||||
});
|
||||
mTimezoneRow = view.findViewById(R.id.timezone_button_row);
|
||||
mStartTimeHome = (TextView) view.findViewById(R.id.start_time_home_tz);
|
||||
mStartDateHome = (TextView) view.findViewById(R.id.start_date_home_tz);
|
||||
mEndTimeHome = (TextView) view.findViewById(R.id.end_time_home_tz);
|
||||
mEndDateHome = (TextView) view.findViewById(R.id.end_date_home_tz);
|
||||
mAllDayCheckBox = (CheckBox) view.findViewById(R.id.is_all_day);
|
||||
mRruleButton = (Button) view.findViewById(R.id.rrule);
|
||||
mAvailabilitySpinner = (Spinner) view.findViewById(R.id.availability);
|
||||
mAccessLevelSpinner = (Spinner) view.findViewById(R.id.visibility);
|
||||
mCalendarSelectorGroup = view.findViewById(R.id.calendar_selector_group);
|
||||
mCalendarSelectorWrapper = view.findViewById(R.id.calendar_selector_wrapper);
|
||||
mCalendarStaticGroup = view.findViewById(R.id.calendar_group);
|
||||
mRemindersGroup = view.findViewById(R.id.reminders_row);
|
||||
mResponseGroup = view.findViewById(R.id.response_row);
|
||||
mOrganizerGroup = view.findViewById(R.id.organizer_row);
|
||||
mAttendeesGroup = view.findViewById(R.id.add_attendees_row);
|
||||
mLocationGroup = view.findViewById(R.id.where_row);
|
||||
mDescriptionGroup = view.findViewById(R.id.description_row);
|
||||
mStartHomeGroup = view.findViewById(R.id.from_row_home_tz);
|
||||
mEndHomeGroup = view.findViewById(R.id.to_row_home_tz);
|
||||
mAttendeesList = (MultiAutoCompleteTextView) view.findViewById(R.id.attendees);
|
||||
|
||||
// Cache the start and end millis so that we limit the number
|
||||
// of calls to normalize() and toMillis(), which are fairly
|
||||
// expensive.
|
||||
long startMillis;
|
||||
long endMillis;
|
||||
if (mView == mStartTimeButton) {
|
||||
// The start time was changed.
|
||||
int hourDuration = endTime.hour - startTime.hour;
|
||||
int minuteDuration = endTime.minute - startTime.minute;
|
||||
mColorPickerNewEvent = view.findViewById(R.id.change_color_new_event);
|
||||
mColorPickerExistingEvent = view.findViewById(R.id.change_color_existing_event);
|
||||
|
||||
startTime.hour = hourOfDay;
|
||||
startTime.minute = minute;
|
||||
startMillis = startTime.normalize(true);
|
||||
|
||||
// Also update the end time to keep the duration constant.
|
||||
endTime.hour = hourOfDay + hourDuration;
|
||||
endTime.minute = minute + minuteDuration;
|
||||
|
||||
// Update tz in case the start time switched from/to DLS
|
||||
populateTimezone(startMillis);
|
||||
} else {
|
||||
// The end time was changed.
|
||||
startMillis = startTime.toMillis(true);
|
||||
endTime.hour = hourOfDay;
|
||||
endTime.minute = minute;
|
||||
|
||||
// Move to the start time if the end time is before the start
|
||||
// time.
|
||||
if (endTime.before(startTime)) {
|
||||
endTime.monthDay = startTime.monthDay + 1;
|
||||
mTitleTextView.setTag(mTitleTextView.getBackground());
|
||||
mLocationTextView.setTag(mLocationTextView.getBackground());
|
||||
mLocationAdapter = new EventLocationAdapter(activity);
|
||||
mLocationTextView.setAdapter(mLocationAdapter);
|
||||
mLocationTextView.setOnEditorActionListener(new OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
// Dismiss the suggestions dropdown. Return false so the other
|
||||
// side effects still occur (soft keyboard going away, etc.).
|
||||
mLocationTextView.dismissDropDown();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mAvailabilityExplicitlySet = false;
|
||||
mAllDayChangingAvailability = false;
|
||||
mAvailabilityCurrentlySelected = -1;
|
||||
mAvailabilitySpinner.setOnItemSelectedListener(
|
||||
new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent,
|
||||
View view, int position, long id) {
|
||||
// The spinner's onItemSelected gets called while it is being
|
||||
// initialized to the first item, and when we explicitly set it
|
||||
// in the allDay checkbox toggling, so we need these checks to
|
||||
// find out when the spinner is actually being clicked.
|
||||
|
||||
// Set the initial selection.
|
||||
if (mAvailabilityCurrentlySelected == -1) {
|
||||
mAvailabilityCurrentlySelected = position;
|
||||
}
|
||||
|
||||
if (mAvailabilityCurrentlySelected != position &&
|
||||
!mAllDayChangingAvailability) {
|
||||
mAvailabilityExplicitlySet = true;
|
||||
} else {
|
||||
mAvailabilityCurrentlySelected = position;
|
||||
mAllDayChangingAvailability = false;
|
||||
}
|
||||
// Call populateTimezone if we support end time zone as well
|
||||
}
|
||||
|
||||
endMillis = endTime.normalize(true);
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> arg0) {
|
||||
}
|
||||
});
|
||||
|
||||
setDate(mEndDateButton, endMillis);
|
||||
setTime(mStartTimeButton, startMillis);
|
||||
setTime(mEndTimeButton, endMillis);
|
||||
updateHomeTime();
|
||||
|
||||
mDescriptionTextView.setTag(mDescriptionTextView.getBackground());
|
||||
mAttendeesList.setTag(mAttendeesList.getBackground());
|
||||
mOriginalPadding[0] = mLocationTextView.getPaddingLeft();
|
||||
mOriginalPadding[1] = mLocationTextView.getPaddingTop();
|
||||
mOriginalPadding[2] = mLocationTextView.getPaddingRight();
|
||||
mOriginalPadding[3] = mLocationTextView.getPaddingBottom();
|
||||
mEditViewList.add(mTitleTextView);
|
||||
mEditViewList.add(mLocationTextView);
|
||||
mEditViewList.add(mDescriptionTextView);
|
||||
mEditViewList.add(mAttendeesList);
|
||||
|
||||
mViewOnlyList.add(view.findViewById(R.id.when_row));
|
||||
mViewOnlyList.add(view.findViewById(R.id.timezone_textview_row));
|
||||
|
||||
mEditOnlyList.add(view.findViewById(R.id.all_day_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.availability_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.visibility_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.from_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.to_row));
|
||||
mEditOnlyList.add(mTimezoneRow);
|
||||
mEditOnlyList.add(mStartHomeGroup);
|
||||
mEditOnlyList.add(mEndHomeGroup);
|
||||
|
||||
mResponseRadioGroup = (RadioGroup) view.findViewById(R.id.response_value);
|
||||
mRemindersContainer = (LinearLayout) view.findViewById(R.id.reminder_items_container);
|
||||
|
||||
mTimezone = Utils.getTimeZone(activity, null);
|
||||
mIsMultipane = activity.getResources().getBoolean(R.bool.tablet_config);
|
||||
mStartTime = new Time(mTimezone);
|
||||
mEndTime = new Time(mTimezone);
|
||||
mEmailValidator = new Rfc822Validator(null);
|
||||
initMultiAutoCompleteTextView((RecipientEditTextView) mAttendeesList);
|
||||
|
||||
// Display loading screen
|
||||
setModel(null);
|
||||
|
||||
FragmentManager fm = activity.getFragmentManager();
|
||||
RecurrencePickerDialog rpd = (RecurrencePickerDialog) fm
|
||||
.findFragmentByTag(FRAG_TAG_RECUR_PICKER);
|
||||
if (rpd != null) {
|
||||
rpd.setOnRecurrenceSetListener(this);
|
||||
}
|
||||
TimeZonePickerDialog tzpd = (TimeZonePickerDialog) fm
|
||||
.findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER);
|
||||
if (tzpd != null) {
|
||||
tzpd.setOnTimeZoneSetListener(this);
|
||||
}
|
||||
TimePickerDialog tpd = (TimePickerDialog) fm.findFragmentByTag(FRAG_TAG_TIME_PICKER);
|
||||
if (tpd != null) {
|
||||
View v;
|
||||
mTimeSelectedWasStartTime = timeSelectedWasStartTime;
|
||||
if (timeSelectedWasStartTime) {
|
||||
v = mStartTimeButton;
|
||||
} else {
|
||||
v = mEndTimeButton;
|
||||
}
|
||||
tpd.setOnTimeSetListener(new TimeListener(v));
|
||||
}
|
||||
mDatePickerDialog = (DatePickerDialog) fm.findFragmentByTag(FRAG_TAG_DATE_PICKER);
|
||||
if (mDatePickerDialog != null) {
|
||||
View v;
|
||||
mDateSelectedWasStartDate = dateSelectedWasStartDate;
|
||||
if (dateSelectedWasStartDate) {
|
||||
v = mStartDateButton;
|
||||
} else {
|
||||
v = mEndDateButton;
|
||||
}
|
||||
mDatePickerDialog.setOnDateSetListener(new DateListener(v));
|
||||
}
|
||||
}
|
||||
|
||||
private class TimeClickListener implements View.OnClickListener {
|
||||
private Time mTime;
|
||||
/**
|
||||
* Loads an integer array asset into a list.
|
||||
*/
|
||||
private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
|
||||
int[] vals = r.getIntArray(resNum);
|
||||
int size = vals.length;
|
||||
ArrayList<Integer> list = new ArrayList<Integer>(size);
|
||||
|
||||
public TimeClickListener(Time time) {
|
||||
mTime = time;
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.add(vals[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
TimePickerDialog dialog;
|
||||
if (v == mStartTimeButton) {
|
||||
mTimeSelectedWasStartTime = true;
|
||||
if (mStartTimePickerDialog == null) {
|
||||
mStartTimePickerDialog = TimePickerDialog.newInstance(new TimeListener(v),
|
||||
mTime.hour, mTime.minute, DateFormat.is24HourFormat(mActivity));
|
||||
} else {
|
||||
mStartTimePickerDialog.setStartTime(mTime.hour, mTime.minute);
|
||||
}
|
||||
dialog = mStartTimePickerDialog;
|
||||
} else {
|
||||
mTimeSelectedWasStartTime = false;
|
||||
if (mEndTimePickerDialog == null) {
|
||||
mEndTimePickerDialog = TimePickerDialog.newInstance(new TimeListener(v),
|
||||
mTime.hour, mTime.minute, DateFormat.is24HourFormat(mActivity));
|
||||
} else {
|
||||
mEndTimePickerDialog.setStartTime(mTime.hour, mTime.minute);
|
||||
}
|
||||
dialog = mEndTimePickerDialog;
|
||||
|
||||
}
|
||||
|
||||
final FragmentManager fm = mActivity.getFragmentManager();
|
||||
fm.executePendingTransactions();
|
||||
|
||||
if (dialog != null && !dialog.isAdded()) {
|
||||
dialog.show(fm, FRAG_TAG_TIME_PICKER);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private class DateListener implements OnDateSetListener {
|
||||
View mView;
|
||||
|
||||
public DateListener(View view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDateSet(DatePickerDialog view, int year, int month, int monthDay) {
|
||||
Log.d(TAG, "onDateSet: " + year + " " + month + " " + monthDay);
|
||||
// Cache the member variables locally to avoid inner class overhead.
|
||||
Time startTime = mStartTime;
|
||||
Time endTime = mEndTime;
|
||||
|
||||
// Cache the start and end millis so that we limit the number
|
||||
// of calls to normalize() and toMillis(), which are fairly
|
||||
// expensive.
|
||||
long startMillis;
|
||||
long endMillis;
|
||||
if (mView == mStartDateButton) {
|
||||
// The start date was changed.
|
||||
int yearDuration = endTime.year - startTime.year;
|
||||
int monthDuration = endTime.month - startTime.month;
|
||||
int monthDayDuration = endTime.monthDay - startTime.monthDay;
|
||||
|
||||
startTime.year = year;
|
||||
startTime.month = month;
|
||||
startTime.monthDay = monthDay;
|
||||
startMillis = startTime.normalize(true);
|
||||
|
||||
// Also update the end date to keep the duration constant.
|
||||
endTime.year = year + yearDuration;
|
||||
endTime.month = month + monthDuration;
|
||||
endTime.monthDay = monthDay + monthDayDuration;
|
||||
endMillis = endTime.normalize(true);
|
||||
|
||||
// If the start date has changed then update the repeats.
|
||||
populateRepeats();
|
||||
|
||||
// Update tz in case the start time switched from/to DLS
|
||||
populateTimezone(startMillis);
|
||||
} else {
|
||||
// The end date was changed.
|
||||
startMillis = startTime.toMillis(true);
|
||||
endTime.year = year;
|
||||
endTime.month = month;
|
||||
endTime.monthDay = monthDay;
|
||||
endMillis = endTime.normalize(true);
|
||||
|
||||
// Do not allow an event to have an end time before the start
|
||||
// time.
|
||||
if (endTime.before(startTime)) {
|
||||
endTime.set(startTime);
|
||||
endMillis = startMillis;
|
||||
}
|
||||
// Call populateTimezone if we support end time zone as well
|
||||
}
|
||||
|
||||
setDate(mStartDateButton, startMillis);
|
||||
setDate(mEndDateButton, endMillis);
|
||||
setTime(mEndTimeButton, endMillis); // In case end time had to be
|
||||
// reset
|
||||
updateHomeTime();
|
||||
}
|
||||
/**
|
||||
* Loads a String array asset into a list.
|
||||
*/
|
||||
private static ArrayList<String> loadStringArray(Resources r, int resNum) {
|
||||
String[] labels = r.getStringArray(resNum);
|
||||
ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
|
||||
return list;
|
||||
}
|
||||
|
||||
// Fills in the date and time fields
|
||||
@ -489,65 +519,6 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
mRruleButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
private class DateClickListener implements View.OnClickListener {
|
||||
private Time mTime;
|
||||
|
||||
public DateClickListener(Time time) {
|
||||
mTime = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
if (v == mStartDateButton) {
|
||||
mDateSelectedWasStartDate = true;
|
||||
} else {
|
||||
mDateSelectedWasStartDate = false;
|
||||
}
|
||||
|
||||
final DateListener listener = new DateListener(v);
|
||||
if (mDatePickerDialog != null) {
|
||||
mDatePickerDialog.dismiss();
|
||||
}
|
||||
mDatePickerDialog = DatePickerDialog.newInstance(listener,
|
||||
mTime.year, mTime.month, mTime.monthDay);
|
||||
mDatePickerDialog.setFirstDayOfWeek(Utils.getFirstDayOfWeekAsCalendar(mActivity));
|
||||
mDatePickerDialog.setYearRange(Utils.YEAR_MIN, Utils.YEAR_MAX);
|
||||
mDatePickerDialog.show(mActivity.getFragmentManager(), FRAG_TAG_DATE_PICKER);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CalendarsAdapter extends ResourceCursorAdapter {
|
||||
public CalendarsAdapter(Context context, int resourceId, Cursor c) {
|
||||
super(context, resourceId, c);
|
||||
setDropDownViewResource(R.layout.calendars_dropdown_item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
View colorBar = view.findViewById(R.id.color);
|
||||
int colorColumn = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
|
||||
int nameColumn = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME);
|
||||
int ownerColumn = cursor.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
|
||||
if (colorBar != null) {
|
||||
colorBar.setBackgroundColor(Utils.getDisplayColorFromColor(cursor
|
||||
.getInt(colorColumn)));
|
||||
}
|
||||
|
||||
TextView name = (TextView) view.findViewById(R.id.calendar_name);
|
||||
if (name != null) {
|
||||
String displayName = cursor.getString(nameColumn);
|
||||
name.setText(displayName);
|
||||
|
||||
TextView accountName = (TextView) view.findViewById(R.id.account_name);
|
||||
if (accountName != null) {
|
||||
accountName.setText(cursor.getString(ownerColumn));
|
||||
accountName.setVisibility(TextView.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does prep steps for saving a calendar event.
|
||||
*
|
||||
@ -757,204 +728,6 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
return true;
|
||||
}
|
||||
|
||||
public EditEventView(Activity activity, View view, EditDoneRunnable done,
|
||||
boolean timeSelectedWasStartTime, boolean dateSelectedWasStartDate) {
|
||||
|
||||
mActivity = activity;
|
||||
mView = view;
|
||||
mDone = done;
|
||||
|
||||
// cache top level view elements
|
||||
mLoadingMessage = (TextView) view.findViewById(R.id.loading_message);
|
||||
mScrollView = (ScrollView) view.findViewById(R.id.scroll_view);
|
||||
|
||||
// cache all the widgets
|
||||
mCalendarsSpinner = (Spinner) view.findViewById(R.id.calendars_spinner);
|
||||
mTitleTextView = (TextView) view.findViewById(R.id.title);
|
||||
mLocationTextView = (AutoCompleteTextView) view.findViewById(R.id.location);
|
||||
mDescriptionTextView = (TextView) view.findViewById(R.id.description);
|
||||
mTimezoneLabel = (TextView) view.findViewById(R.id.timezone_label);
|
||||
mStartDateButton = (Button) view.findViewById(R.id.start_date);
|
||||
mEndDateButton = (Button) view.findViewById(R.id.end_date);
|
||||
mWhenView = (TextView) mView.findViewById(R.id.when);
|
||||
mTimezoneTextView = (TextView) mView.findViewById(R.id.timezone_textView);
|
||||
mStartTimeButton = (Button) view.findViewById(R.id.start_time);
|
||||
mEndTimeButton = (Button) view.findViewById(R.id.end_time);
|
||||
mTimezoneButton = (Button) view.findViewById(R.id.timezone_button);
|
||||
mTimezoneButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showTimezoneDialog();
|
||||
}
|
||||
});
|
||||
mTimezoneRow = view.findViewById(R.id.timezone_button_row);
|
||||
mStartTimeHome = (TextView) view.findViewById(R.id.start_time_home_tz);
|
||||
mStartDateHome = (TextView) view.findViewById(R.id.start_date_home_tz);
|
||||
mEndTimeHome = (TextView) view.findViewById(R.id.end_time_home_tz);
|
||||
mEndDateHome = (TextView) view.findViewById(R.id.end_date_home_tz);
|
||||
mAllDayCheckBox = (CheckBox) view.findViewById(R.id.is_all_day);
|
||||
mRruleButton = (Button) view.findViewById(R.id.rrule);
|
||||
mAvailabilitySpinner = (Spinner) view.findViewById(R.id.availability);
|
||||
mAccessLevelSpinner = (Spinner) view.findViewById(R.id.visibility);
|
||||
mCalendarSelectorGroup = view.findViewById(R.id.calendar_selector_group);
|
||||
mCalendarSelectorWrapper = view.findViewById(R.id.calendar_selector_wrapper);
|
||||
mCalendarStaticGroup = view.findViewById(R.id.calendar_group);
|
||||
mRemindersGroup = view.findViewById(R.id.reminders_row);
|
||||
mResponseGroup = view.findViewById(R.id.response_row);
|
||||
mOrganizerGroup = view.findViewById(R.id.organizer_row);
|
||||
mAttendeesGroup = view.findViewById(R.id.add_attendees_row);
|
||||
mLocationGroup = view.findViewById(R.id.where_row);
|
||||
mDescriptionGroup = view.findViewById(R.id.description_row);
|
||||
mStartHomeGroup = view.findViewById(R.id.from_row_home_tz);
|
||||
mEndHomeGroup = view.findViewById(R.id.to_row_home_tz);
|
||||
mAttendeesList = (MultiAutoCompleteTextView) view.findViewById(R.id.attendees);
|
||||
|
||||
mColorPickerNewEvent = view.findViewById(R.id.change_color_new_event);
|
||||
mColorPickerExistingEvent = view.findViewById(R.id.change_color_existing_event);
|
||||
|
||||
mTitleTextView.setTag(mTitleTextView.getBackground());
|
||||
mLocationTextView.setTag(mLocationTextView.getBackground());
|
||||
mLocationAdapter = new EventLocationAdapter(activity);
|
||||
mLocationTextView.setAdapter(mLocationAdapter);
|
||||
mLocationTextView.setOnEditorActionListener(new OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
// Dismiss the suggestions dropdown. Return false so the other
|
||||
// side effects still occur (soft keyboard going away, etc.).
|
||||
mLocationTextView.dismissDropDown();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mAvailabilityExplicitlySet = false;
|
||||
mAllDayChangingAvailability = false;
|
||||
mAvailabilityCurrentlySelected = -1;
|
||||
mAvailabilitySpinner.setOnItemSelectedListener(
|
||||
new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent,
|
||||
View view, int position, long id) {
|
||||
// The spinner's onItemSelected gets called while it is being
|
||||
// initialized to the first item, and when we explicitly set it
|
||||
// in the allDay checkbox toggling, so we need these checks to
|
||||
// find out when the spinner is actually being clicked.
|
||||
|
||||
// Set the initial selection.
|
||||
if (mAvailabilityCurrentlySelected == -1) {
|
||||
mAvailabilityCurrentlySelected = position;
|
||||
}
|
||||
|
||||
if (mAvailabilityCurrentlySelected != position &&
|
||||
!mAllDayChangingAvailability) {
|
||||
mAvailabilityExplicitlySet = true;
|
||||
} else {
|
||||
mAvailabilityCurrentlySelected = position;
|
||||
mAllDayChangingAvailability = false;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> arg0) { }
|
||||
});
|
||||
|
||||
|
||||
mDescriptionTextView.setTag(mDescriptionTextView.getBackground());
|
||||
mAttendeesList.setTag(mAttendeesList.getBackground());
|
||||
mOriginalPadding[0] = mLocationTextView.getPaddingLeft();
|
||||
mOriginalPadding[1] = mLocationTextView.getPaddingTop();
|
||||
mOriginalPadding[2] = mLocationTextView.getPaddingRight();
|
||||
mOriginalPadding[3] = mLocationTextView.getPaddingBottom();
|
||||
mEditViewList.add(mTitleTextView);
|
||||
mEditViewList.add(mLocationTextView);
|
||||
mEditViewList.add(mDescriptionTextView);
|
||||
mEditViewList.add(mAttendeesList);
|
||||
|
||||
mViewOnlyList.add(view.findViewById(R.id.when_row));
|
||||
mViewOnlyList.add(view.findViewById(R.id.timezone_textview_row));
|
||||
|
||||
mEditOnlyList.add(view.findViewById(R.id.all_day_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.availability_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.visibility_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.from_row));
|
||||
mEditOnlyList.add(view.findViewById(R.id.to_row));
|
||||
mEditOnlyList.add(mTimezoneRow);
|
||||
mEditOnlyList.add(mStartHomeGroup);
|
||||
mEditOnlyList.add(mEndHomeGroup);
|
||||
|
||||
mResponseRadioGroup = (RadioGroup) view.findViewById(R.id.response_value);
|
||||
mRemindersContainer = (LinearLayout) view.findViewById(R.id.reminder_items_container);
|
||||
|
||||
mTimezone = Utils.getTimeZone(activity, null);
|
||||
mIsMultipane = activity.getResources().getBoolean(R.bool.tablet_config);
|
||||
mStartTime = new Time(mTimezone);
|
||||
mEndTime = new Time(mTimezone);
|
||||
mEmailValidator = new Rfc822Validator(null);
|
||||
initMultiAutoCompleteTextView((RecipientEditTextView) mAttendeesList);
|
||||
|
||||
// Display loading screen
|
||||
setModel(null);
|
||||
|
||||
FragmentManager fm = activity.getFragmentManager();
|
||||
RecurrencePickerDialog rpd = (RecurrencePickerDialog) fm
|
||||
.findFragmentByTag(FRAG_TAG_RECUR_PICKER);
|
||||
if (rpd != null) {
|
||||
rpd.setOnRecurrenceSetListener(this);
|
||||
}
|
||||
TimeZonePickerDialog tzpd = (TimeZonePickerDialog) fm
|
||||
.findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER);
|
||||
if (tzpd != null) {
|
||||
tzpd.setOnTimeZoneSetListener(this);
|
||||
}
|
||||
TimePickerDialog tpd = (TimePickerDialog) fm.findFragmentByTag(FRAG_TAG_TIME_PICKER);
|
||||
if (tpd != null) {
|
||||
View v;
|
||||
mTimeSelectedWasStartTime = timeSelectedWasStartTime;
|
||||
if (timeSelectedWasStartTime) {
|
||||
v = mStartTimeButton;
|
||||
} else {
|
||||
v = mEndTimeButton;
|
||||
}
|
||||
tpd.setOnTimeSetListener(new TimeListener(v));
|
||||
}
|
||||
mDatePickerDialog = (DatePickerDialog) fm.findFragmentByTag(FRAG_TAG_DATE_PICKER);
|
||||
if (mDatePickerDialog != null) {
|
||||
View v;
|
||||
mDateSelectedWasStartDate = dateSelectedWasStartDate;
|
||||
if (dateSelectedWasStartDate) {
|
||||
v = mStartDateButton;
|
||||
} else {
|
||||
v = mEndDateButton;
|
||||
}
|
||||
mDatePickerDialog.setOnDateSetListener(new DateListener(v));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads an integer array asset into a list.
|
||||
*/
|
||||
private static ArrayList<Integer> loadIntegerArray(Resources r, int resNum) {
|
||||
int[] vals = r.getIntArray(resNum);
|
||||
int size = vals.length;
|
||||
ArrayList<Integer> list = new ArrayList<Integer>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.add(vals[i]);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a String array asset into a list.
|
||||
*/
|
||||
private static ArrayList<String> loadStringArray(Resources r, int resNum) {
|
||||
String[] labels = r.getStringArray(resNum);
|
||||
ArrayList<String> list = new ArrayList<String>(Arrays.asList(labels));
|
||||
return list;
|
||||
}
|
||||
|
||||
private void prepareAvailability() {
|
||||
Resources r = mActivity.getResources();
|
||||
|
||||
@ -1575,14 +1348,6 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* From com.google.android.gm.ComposeActivity Implements special address
|
||||
* cleanup rules: The first space key entry following an "@" symbol that is
|
||||
* followed by any combination of letters and symbols, including one+ dots
|
||||
* and zero commas, should insert an extra comma (followed by the space).
|
||||
*/
|
||||
private static InputFilter[] sRecipientFilters = new InputFilter[] { new Rfc822InputFilter() };
|
||||
|
||||
private void setDate(TextView view, long millis) {
|
||||
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
|
||||
| DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_MONTH
|
||||
@ -1841,4 +1606,227 @@ public class EditEventView implements View.OnClickListener, DialogInterface.OnCa
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
|
||||
public static class CalendarsAdapter extends ResourceCursorAdapter {
|
||||
public CalendarsAdapter(Context context, int resourceId, Cursor c) {
|
||||
super(context, resourceId, c);
|
||||
setDropDownViewResource(R.layout.calendars_dropdown_item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
View colorBar = view.findViewById(R.id.color);
|
||||
int colorColumn = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
|
||||
int nameColumn = cursor.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME);
|
||||
int ownerColumn = cursor.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
|
||||
if (colorBar != null) {
|
||||
colorBar.setBackgroundColor(Utils.getDisplayColorFromColor(cursor
|
||||
.getInt(colorColumn)));
|
||||
}
|
||||
|
||||
TextView name = (TextView) view.findViewById(R.id.calendar_name);
|
||||
if (name != null) {
|
||||
String displayName = cursor.getString(nameColumn);
|
||||
name.setText(displayName);
|
||||
|
||||
TextView accountName = (TextView) view.findViewById(R.id.account_name);
|
||||
if (accountName != null) {
|
||||
accountName.setText(cursor.getString(ownerColumn));
|
||||
accountName.setVisibility(TextView.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This class is used to update the time buttons. */
|
||||
private class TimeListener implements OnTimeSetListener {
|
||||
private View mView;
|
||||
|
||||
public TimeListener(View view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
|
||||
// Cache the member variables locally to avoid inner class overhead.
|
||||
Time startTime = mStartTime;
|
||||
Time endTime = mEndTime;
|
||||
|
||||
// Cache the start and end millis so that we limit the number
|
||||
// of calls to normalize() and toMillis(), which are fairly
|
||||
// expensive.
|
||||
long startMillis;
|
||||
long endMillis;
|
||||
if (mView == mStartTimeButton) {
|
||||
// The start time was changed.
|
||||
int hourDuration = endTime.hour - startTime.hour;
|
||||
int minuteDuration = endTime.minute - startTime.minute;
|
||||
|
||||
startTime.hour = hourOfDay;
|
||||
startTime.minute = minute;
|
||||
startMillis = startTime.normalize(true);
|
||||
|
||||
// Also update the end time to keep the duration constant.
|
||||
endTime.hour = hourOfDay + hourDuration;
|
||||
endTime.minute = minute + minuteDuration;
|
||||
|
||||
// Update tz in case the start time switched from/to DLS
|
||||
populateTimezone(startMillis);
|
||||
} else {
|
||||
// The end time was changed.
|
||||
startMillis = startTime.toMillis(true);
|
||||
endTime.hour = hourOfDay;
|
||||
endTime.minute = minute;
|
||||
|
||||
// Move to the start time if the end time is before the start
|
||||
// time.
|
||||
if (endTime.before(startTime)) {
|
||||
endTime.monthDay = startTime.monthDay + 1;
|
||||
}
|
||||
// Call populateTimezone if we support end time zone as well
|
||||
}
|
||||
|
||||
endMillis = endTime.normalize(true);
|
||||
|
||||
setDate(mEndDateButton, endMillis);
|
||||
setTime(mStartTimeButton, startMillis);
|
||||
setTime(mEndTimeButton, endMillis);
|
||||
updateHomeTime();
|
||||
}
|
||||
}
|
||||
|
||||
private class TimeClickListener implements View.OnClickListener {
|
||||
private Time mTime;
|
||||
|
||||
public TimeClickListener(Time time) {
|
||||
mTime = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
TimePickerDialog dialog;
|
||||
if (v == mStartTimeButton) {
|
||||
mTimeSelectedWasStartTime = true;
|
||||
if (mStartTimePickerDialog == null) {
|
||||
mStartTimePickerDialog = TimePickerDialog.newInstance(new TimeListener(v),
|
||||
mTime.hour, mTime.minute, DateFormat.is24HourFormat(mActivity));
|
||||
} else {
|
||||
mStartTimePickerDialog.setStartTime(mTime.hour, mTime.minute);
|
||||
}
|
||||
dialog = mStartTimePickerDialog;
|
||||
} else {
|
||||
mTimeSelectedWasStartTime = false;
|
||||
if (mEndTimePickerDialog == null) {
|
||||
mEndTimePickerDialog = TimePickerDialog.newInstance(new TimeListener(v),
|
||||
mTime.hour, mTime.minute, DateFormat.is24HourFormat(mActivity));
|
||||
} else {
|
||||
mEndTimePickerDialog.setStartTime(mTime.hour, mTime.minute);
|
||||
}
|
||||
dialog = mEndTimePickerDialog;
|
||||
|
||||
}
|
||||
|
||||
final FragmentManager fm = mActivity.getFragmentManager();
|
||||
fm.executePendingTransactions();
|
||||
|
||||
if (dialog != null && !dialog.isAdded()) {
|
||||
dialog.show(fm, FRAG_TAG_TIME_PICKER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DateListener implements OnDateSetListener {
|
||||
View mView;
|
||||
|
||||
public DateListener(View view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDateSet(DatePickerDialog view, int year, int month, int monthDay) {
|
||||
Log.d(TAG, "onDateSet: " + year + " " + month + " " + monthDay);
|
||||
// Cache the member variables locally to avoid inner class overhead.
|
||||
Time startTime = mStartTime;
|
||||
Time endTime = mEndTime;
|
||||
|
||||
// Cache the start and end millis so that we limit the number
|
||||
// of calls to normalize() and toMillis(), which are fairly
|
||||
// expensive.
|
||||
long startMillis;
|
||||
long endMillis;
|
||||
if (mView == mStartDateButton) {
|
||||
// The start date was changed.
|
||||
int yearDuration = endTime.year - startTime.year;
|
||||
int monthDuration = endTime.month - startTime.month;
|
||||
int monthDayDuration = endTime.monthDay - startTime.monthDay;
|
||||
|
||||
startTime.year = year;
|
||||
startTime.month = month;
|
||||
startTime.monthDay = monthDay;
|
||||
startMillis = startTime.normalize(true);
|
||||
|
||||
// Also update the end date to keep the duration constant.
|
||||
endTime.year = year + yearDuration;
|
||||
endTime.month = month + monthDuration;
|
||||
endTime.monthDay = monthDay + monthDayDuration;
|
||||
endMillis = endTime.normalize(true);
|
||||
|
||||
// If the start date has changed then update the repeats.
|
||||
populateRepeats();
|
||||
|
||||
// Update tz in case the start time switched from/to DLS
|
||||
populateTimezone(startMillis);
|
||||
} else {
|
||||
// The end date was changed.
|
||||
startMillis = startTime.toMillis(true);
|
||||
endTime.year = year;
|
||||
endTime.month = month;
|
||||
endTime.monthDay = monthDay;
|
||||
endMillis = endTime.normalize(true);
|
||||
|
||||
// Do not allow an event to have an end time before the start
|
||||
// time.
|
||||
if (endTime.before(startTime)) {
|
||||
endTime.set(startTime);
|
||||
endMillis = startMillis;
|
||||
}
|
||||
// Call populateTimezone if we support end time zone as well
|
||||
}
|
||||
|
||||
setDate(mStartDateButton, startMillis);
|
||||
setDate(mEndDateButton, endMillis);
|
||||
setTime(mEndTimeButton, endMillis); // In case end time had to be
|
||||
// reset
|
||||
updateHomeTime();
|
||||
}
|
||||
}
|
||||
|
||||
private class DateClickListener implements View.OnClickListener {
|
||||
private Time mTime;
|
||||
|
||||
public DateClickListener(Time time) {
|
||||
mTime = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
if (v == mStartDateButton) {
|
||||
mDateSelectedWasStartDate = true;
|
||||
} else {
|
||||
mDateSelectedWasStartDate = false;
|
||||
}
|
||||
|
||||
final DateListener listener = new DateListener(v);
|
||||
if (mDatePickerDialog != null) {
|
||||
mDatePickerDialog.dismiss();
|
||||
}
|
||||
mDatePickerDialog = DatePickerDialog.newInstance(listener,
|
||||
mTime.year, mTime.month, mTime.monthDay);
|
||||
mDatePickerDialog.setFirstDayOfWeek(Utils.getFirstDayOfWeekAsCalendar(mActivity));
|
||||
mDatePickerDialog.setYearRange(Utils.YEAR_MIN, Utils.YEAR_MAX);
|
||||
mDatePickerDialog.show(mActivity.getFragmentManager(), FRAG_TAG_DATE_PICKER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,10 @@ import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.colorpicker.ColorPickerDialog;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* A dialog which displays event colors, with an additional button for the calendar color.
|
||||
*/
|
||||
|
@ -39,8 +39,6 @@ import android.widget.Filterable;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -50,6 +48,8 @@ import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
// TODO: limit length of dropdown to stop at the soft keyboard
|
||||
// TODO: history icon resize asset
|
||||
|
||||
@ -59,40 +59,6 @@ import java.util.concurrent.ExecutionException;
|
||||
public class EventLocationAdapter extends ArrayAdapter<EventLocationAdapter.Result>
|
||||
implements Filterable {
|
||||
private static final String TAG = "EventLocationAdapter";
|
||||
|
||||
/**
|
||||
* Internal class for containing info for an item in the auto-complete results.
|
||||
*/
|
||||
public static class Result {
|
||||
private final String mName;
|
||||
private final String mAddress;
|
||||
|
||||
// The default image resource for the icon. This will be null if there should
|
||||
// be no icon (if multiple listings for a contact, only the first one should have the
|
||||
// photo icon).
|
||||
private final Integer mDefaultIcon;
|
||||
|
||||
// The contact photo to use for the icon. This will override the default icon.
|
||||
private final Uri mContactPhotoUri;
|
||||
|
||||
public Result(String displayName, String address, Integer defaultIcon,
|
||||
Uri contactPhotoUri) {
|
||||
this.mName = displayName;
|
||||
this.mAddress = address;
|
||||
this.mDefaultIcon = defaultIcon;
|
||||
this.mContactPhotoUri = contactPhotoUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the autocompleted text.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return mAddress;
|
||||
}
|
||||
}
|
||||
private static ArrayList<Result> EMPTY_LIST = new ArrayList<Result>();
|
||||
|
||||
// Constants for contacts query:
|
||||
// SELECT ... FROM view_data data WHERE ((data1 LIKE 'input%' OR data1 LIKE '%input%' OR
|
||||
// display_name LIKE 'input%' OR display_name LIKE '%input%' )) ORDER BY display_name ASC
|
||||
@ -120,7 +86,6 @@ public class EventLocationAdapter extends ArrayAdapter<EventLocationAdapter.Resu
|
||||
.append(Contacts.DISPLAY_NAME)
|
||||
.append(" LIKE ? )")
|
||||
.toString();
|
||||
|
||||
// Constants for recent locations query (in Events table):
|
||||
// SELECT ... FROM view_events WHERE (eventLocation LIKE 'input%') ORDER BY _id DESC
|
||||
private static final String[] EVENT_PROJECTION = new String[] {
|
||||
@ -134,11 +99,10 @@ public class EventLocationAdapter extends ArrayAdapter<EventLocationAdapter.Resu
|
||||
private static final String LOCATION_WHERE = Events.VISIBLE + "=? AND "
|
||||
+ Events.EVENT_LOCATION + " LIKE ?";
|
||||
private static final int MAX_LOCATION_SUGGESTIONS = 4;
|
||||
|
||||
private static ArrayList<Result> EMPTY_LIST = new ArrayList<Result>();
|
||||
private final ContentResolver mResolver;
|
||||
private final LayoutInflater mInflater;
|
||||
private final ArrayList<Result> mResultList = new ArrayList<Result>();
|
||||
|
||||
// The cache for contacts photos. We don't have to worry about clearing this, as a
|
||||
// new adapter is created for every edit event.
|
||||
private final Map<Uri, Bitmap> mPhotoCache = new HashMap<Uri, Bitmap>();
|
||||
@ -153,6 +117,136 @@ public class EventLocationAdapter extends ArrayAdapter<EventLocationAdapter.Resu
|
||||
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the input string against contacts names and addresses.
|
||||
*
|
||||
* @param resolver The content resolver.
|
||||
* @param input The user-typed input string.
|
||||
* @param addressesRetVal The addresses in the returned result are also returned here
|
||||
* for faster lookup. Pass in an empty set.
|
||||
* @return Ordered list of all the matched results. If there are multiple address matches
|
||||
* for the same contact, they will be listed together in individual items, with only
|
||||
* the first item containing a name/icon.
|
||||
*/
|
||||
private static List<Result> queryContacts(ContentResolver resolver, String input,
|
||||
HashSet<String> addressesRetVal) {
|
||||
String where = null;
|
||||
String[] whereArgs = null;
|
||||
|
||||
// Match any word in contact name or address.
|
||||
if (!TextUtils.isEmpty(input)) {
|
||||
where = CONTACTS_WHERE;
|
||||
String param1 = input + "%";
|
||||
String param2 = "% " + input + "%";
|
||||
whereArgs = new String[]{param1, param2, param1, param2};
|
||||
}
|
||||
|
||||
// Perform the query.
|
||||
Cursor c = resolver.query(CommonDataKinds.StructuredPostal.CONTENT_URI,
|
||||
CONTACTS_PROJECTION, where, whereArgs, Contacts.DISPLAY_NAME + " ASC");
|
||||
|
||||
// Process results. Group together addresses for the same contact.
|
||||
try {
|
||||
Map<String, List<Result>> nameToAddresses = new HashMap<String, List<Result>>();
|
||||
c.moveToPosition(-1);
|
||||
while (c.moveToNext()) {
|
||||
String name = c.getString(CONTACTS_INDEX_DISPLAY_NAME);
|
||||
String address = c.getString(CONTACTS_INDEX_ADDRESS);
|
||||
if (name != null) {
|
||||
|
||||
List<Result> addressesForName = nameToAddresses.get(name);
|
||||
Result result;
|
||||
if (addressesForName == null) {
|
||||
// Determine if there is a photo for the icon.
|
||||
Uri contactPhotoUri = null;
|
||||
if (c.getLong(CONTACTS_INDEX_PHOTO_ID) > 0) {
|
||||
contactPhotoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
|
||||
c.getLong(CONTACTS_INDEX_CONTACT_ID));
|
||||
}
|
||||
|
||||
// First listing for a distinct contact should have the name/icon.
|
||||
addressesForName = new ArrayList<Result>();
|
||||
nameToAddresses.put(name, addressesForName);
|
||||
result = new Result(name, address, R.drawable.ic_contact_picture,
|
||||
contactPhotoUri);
|
||||
} else {
|
||||
// Do not include name/icon in subsequent listings for the same contact.
|
||||
result = new Result(null, address, null, null);
|
||||
}
|
||||
|
||||
addressesForName.add(result);
|
||||
addressesRetVal.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of results.
|
||||
List<Result> allResults = new ArrayList<Result>();
|
||||
for (List<Result> result : nameToAddresses.values()) {
|
||||
allResults.addAll(result);
|
||||
}
|
||||
return allResults;
|
||||
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the input string against recent locations.
|
||||
*/
|
||||
private static List<Result> queryRecentLocations(ContentResolver resolver, String input) {
|
||||
// TODO: also match each word in the address?
|
||||
String filter = input == null ? "" : input + "%";
|
||||
if (filter.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Query all locations prefixed with the constraint. There is no way to insert
|
||||
// 'DISTINCT' or 'GROUP BY' to get rid of dupes, so use post-processing to
|
||||
// remove dupes. We will order query results by descending event ID to show
|
||||
// results that were most recently inputed.
|
||||
Cursor c = resolver.query(Events.CONTENT_URI, EVENT_PROJECTION, LOCATION_WHERE,
|
||||
new String[]{"1", filter}, Events._ID + " DESC");
|
||||
try {
|
||||
List<Result> recentLocations = null;
|
||||
if (c != null) {
|
||||
// Post process query results.
|
||||
recentLocations = processLocationsQueryResults(c);
|
||||
}
|
||||
return recentLocations;
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process the query results to return the first MAX_LOCATION_SUGGESTIONS
|
||||
* unique locations in alphabetical order.
|
||||
* <p/>
|
||||
* TODO: Refactor to share code with the recent titles auto-complete.
|
||||
*/
|
||||
private static List<Result> processLocationsQueryResults(Cursor cursor) {
|
||||
TreeSet<String> locations = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
||||
cursor.moveToPosition(-1);
|
||||
|
||||
// Remove dupes.
|
||||
while ((locations.size() < MAX_LOCATION_SUGGESTIONS) && cursor.moveToNext()) {
|
||||
String location = cursor.getString(EVENT_INDEX_LOCATION).trim();
|
||||
locations.add(location);
|
||||
}
|
||||
|
||||
// Copy the sorted results.
|
||||
List<Result> results = new ArrayList<Result>();
|
||||
for (String location : locations) {
|
||||
results.add(new Result(null, location, R.drawable.ic_history_holo_light, null));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mResultList.size();
|
||||
@ -260,6 +354,38 @@ public class EventLocationAdapter extends ArrayAdapter<EventLocationAdapter.Resu
|
||||
return new LocationFilter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class for containing info for an item in the auto-complete results.
|
||||
*/
|
||||
public static class Result {
|
||||
private final String mName;
|
||||
private final String mAddress;
|
||||
|
||||
// The default image resource for the icon. This will be null if there should
|
||||
// be no icon (if multiple listings for a contact, only the first one should have the
|
||||
// photo icon).
|
||||
private final Integer mDefaultIcon;
|
||||
|
||||
// The contact photo to use for the icon. This will override the default icon.
|
||||
private final Uri mContactPhotoUri;
|
||||
|
||||
public Result(String displayName, String address, Integer defaultIcon,
|
||||
Uri contactPhotoUri) {
|
||||
this.mName = displayName;
|
||||
this.mAddress = address;
|
||||
this.mDefaultIcon = defaultIcon;
|
||||
this.mContactPhotoUri = contactPhotoUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the autocompleted text.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return mAddress;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter implementation for matching the input string against contacts info and
|
||||
* recent locations.
|
||||
@ -339,134 +465,4 @@ public class EventLocationAdapter extends ArrayAdapter<EventLocationAdapter.Resu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the input string against contacts names and addresses.
|
||||
*
|
||||
* @param resolver The content resolver.
|
||||
* @param input The user-typed input string.
|
||||
* @param addressesRetVal The addresses in the returned result are also returned here
|
||||
* for faster lookup. Pass in an empty set.
|
||||
* @return Ordered list of all the matched results. If there are multiple address matches
|
||||
* for the same contact, they will be listed together in individual items, with only
|
||||
* the first item containing a name/icon.
|
||||
*/
|
||||
private static List<Result> queryContacts(ContentResolver resolver, String input,
|
||||
HashSet<String> addressesRetVal) {
|
||||
String where = null;
|
||||
String[] whereArgs = null;
|
||||
|
||||
// Match any word in contact name or address.
|
||||
if (!TextUtils.isEmpty(input)) {
|
||||
where = CONTACTS_WHERE;
|
||||
String param1 = input + "%";
|
||||
String param2 = "% " + input + "%";
|
||||
whereArgs = new String[] {param1, param2, param1, param2};
|
||||
}
|
||||
|
||||
// Perform the query.
|
||||
Cursor c = resolver.query(CommonDataKinds.StructuredPostal.CONTENT_URI,
|
||||
CONTACTS_PROJECTION, where, whereArgs, Contacts.DISPLAY_NAME + " ASC");
|
||||
|
||||
// Process results. Group together addresses for the same contact.
|
||||
try {
|
||||
Map<String, List<Result>> nameToAddresses = new HashMap<String, List<Result>>();
|
||||
c.moveToPosition(-1);
|
||||
while (c.moveToNext()) {
|
||||
String name = c.getString(CONTACTS_INDEX_DISPLAY_NAME);
|
||||
String address = c.getString(CONTACTS_INDEX_ADDRESS);
|
||||
if (name != null) {
|
||||
|
||||
List<Result> addressesForName = nameToAddresses.get(name);
|
||||
Result result;
|
||||
if (addressesForName == null) {
|
||||
// Determine if there is a photo for the icon.
|
||||
Uri contactPhotoUri = null;
|
||||
if (c.getLong(CONTACTS_INDEX_PHOTO_ID) > 0) {
|
||||
contactPhotoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
|
||||
c.getLong(CONTACTS_INDEX_CONTACT_ID));
|
||||
}
|
||||
|
||||
// First listing for a distinct contact should have the name/icon.
|
||||
addressesForName = new ArrayList<Result>();
|
||||
nameToAddresses.put(name, addressesForName);
|
||||
result = new Result(name, address, R.drawable.ic_contact_picture,
|
||||
contactPhotoUri);
|
||||
} else {
|
||||
// Do not include name/icon in subsequent listings for the same contact.
|
||||
result = new Result(null, address, null, null);
|
||||
}
|
||||
|
||||
addressesForName.add(result);
|
||||
addressesRetVal.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of results.
|
||||
List<Result> allResults = new ArrayList<Result>();
|
||||
for (List<Result> result : nameToAddresses.values()) {
|
||||
allResults.addAll(result);
|
||||
}
|
||||
return allResults;
|
||||
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the input string against recent locations.
|
||||
*/
|
||||
private static List<Result> queryRecentLocations(ContentResolver resolver, String input) {
|
||||
// TODO: also match each word in the address?
|
||||
String filter = input == null ? "" : input + "%";
|
||||
if (filter.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Query all locations prefixed with the constraint. There is no way to insert
|
||||
// 'DISTINCT' or 'GROUP BY' to get rid of dupes, so use post-processing to
|
||||
// remove dupes. We will order query results by descending event ID to show
|
||||
// results that were most recently inputed.
|
||||
Cursor c = resolver.query(Events.CONTENT_URI, EVENT_PROJECTION, LOCATION_WHERE,
|
||||
new String[] { "1", filter }, Events._ID + " DESC");
|
||||
try {
|
||||
List<Result> recentLocations = null;
|
||||
if (c != null) {
|
||||
// Post process query results.
|
||||
recentLocations = processLocationsQueryResults(c);
|
||||
}
|
||||
return recentLocations;
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process the query results to return the first MAX_LOCATION_SUGGESTIONS
|
||||
* unique locations in alphabetical order.
|
||||
*
|
||||
* TODO: Refactor to share code with the recent titles auto-complete.
|
||||
*/
|
||||
private static List<Result> processLocationsQueryResults(Cursor cursor) {
|
||||
TreeSet<String> locations = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
||||
cursor.moveToPosition(-1);
|
||||
|
||||
// Remove dupes.
|
||||
while ((locations.size() < MAX_LOCATION_SUGGESTIONS) && cursor.moveToNext()) {
|
||||
String location = cursor.getString(EVENT_INDEX_LOCATION).trim();
|
||||
locations.add(location);
|
||||
}
|
||||
|
||||
// Copy the sorted results.
|
||||
List<Result> results = new ArrayList<Result>();
|
||||
for (String location : locations) {
|
||||
results.add(new Result(null, location, R.drawable.ic_history_holo_light, null));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,6 @@
|
||||
*/
|
||||
package com.android.calendar.event;
|
||||
|
||||
import com.android.calendar.CalendarEventModel.ReminderEntry;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
@ -30,8 +27,12 @@ import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import com.android.calendar.CalendarEventModel.ReminderEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class EventViewUtils {
|
||||
private static final String TAG = "EventViewUtils";
|
||||
|
||||
|
@ -36,11 +36,11 @@ import com.android.calendar.CalendarController.ViewType;
|
||||
import com.android.calendar.Event;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class MonthByWeekAdapter extends SimpleWeeksAdapter {
|
||||
public static final String WEEK_PARAMS_IS_MINI = "mini_month";
|
||||
private static final String TAG = "MonthByWeekAdapter";
|
||||
|
@ -49,7 +49,6 @@ import com.android.calendar.CalendarController.EventInfo;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
import com.android.calendar.Event;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.event.CreateEventDialogFragment;
|
||||
|
||||
@ -58,27 +57,17 @@ import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class MonthByWeekFragment extends SimpleDayPickerFragment implements
|
||||
CalendarController.EventHandler, LoaderManager.LoaderCallbacks<Cursor>, OnScrollListener,
|
||||
OnTouchListener {
|
||||
private static final String TAG = "MonthFragment";
|
||||
private static final String TAG_EVENT_DIALOG = "event_dialog";
|
||||
|
||||
private CreateEventDialogFragment mEventDialog;
|
||||
|
||||
// Selection and selection args for adding event queries
|
||||
private static final String WHERE_CALENDARS_VISIBLE = Calendars.VISIBLE + "=1";
|
||||
private static final String INSTANCES_SORT_ORDER = Instances.START_DAY + ","
|
||||
+ Instances.START_MINUTE + "," + Instances.TITLE;
|
||||
protected static boolean mShowDetailsInMonth = false;
|
||||
|
||||
protected float mMinimumTwoMonthFlingVelocity;
|
||||
protected boolean mIsMiniMonth;
|
||||
protected boolean mHideDeclined;
|
||||
|
||||
protected int mFirstLoadedJulianDay;
|
||||
protected int mLastLoadedJulianDay;
|
||||
|
||||
private static final int WEEKS_BUFFER = 1;
|
||||
// How long to wait after scroll stops before starting the loader
|
||||
// Using scroll duration because scroll state changes don't update
|
||||
@ -87,32 +76,8 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
|
||||
// The minimum time between requeries of the data if the db is
|
||||
// changing
|
||||
private static final int LOADER_THROTTLE_DELAY = 500;
|
||||
|
||||
private CursorLoader mLoader;
|
||||
private Uri mEventUri;
|
||||
protected static boolean mShowDetailsInMonth = false;
|
||||
private final Time mDesiredDay = new Time();
|
||||
|
||||
private volatile boolean mShouldLoad = true;
|
||||
private boolean mUserScrolled = false;
|
||||
|
||||
private int mEventsLoadingDelay;
|
||||
private boolean mShowCalendarControls;
|
||||
private boolean mIsDetached;
|
||||
|
||||
private Handler mEventDialogHandler = new Handler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
final FragmentManager manager = getFragmentManager();
|
||||
if (manager != null) {
|
||||
Time day = (Time) msg.obj;
|
||||
mEventDialog = new CreateEventDialogFragment(day);
|
||||
mEventDialog.show(manager, TAG_EVENT_DIALOG);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final Runnable mTZUpdater = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -129,8 +94,15 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
protected float mMinimumTwoMonthFlingVelocity;
|
||||
protected boolean mIsMiniMonth;
|
||||
protected boolean mHideDeclined;
|
||||
protected int mFirstLoadedJulianDay;
|
||||
protected int mLastLoadedJulianDay;
|
||||
private CreateEventDialogFragment mEventDialog;
|
||||
private CursorLoader mLoader;
|
||||
private Uri mEventUri;
|
||||
private volatile boolean mShouldLoad = true;
|
||||
private final Runnable mUpdateLoader = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -153,6 +125,10 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
|
||||
}
|
||||
}
|
||||
};
|
||||
private boolean mUserScrolled = false;
|
||||
private int mEventsLoadingDelay;
|
||||
private boolean mShowCalendarControls;
|
||||
private boolean mIsDetached;
|
||||
// Used to load the events when a delay is needed
|
||||
Runnable mLoadingRunnable = new Runnable() {
|
||||
@Override
|
||||
@ -163,7 +139,28 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
|
||||
}
|
||||
}
|
||||
};
|
||||
private Handler mEventDialogHandler = new Handler() {
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
final FragmentManager manager = getFragmentManager();
|
||||
if (manager != null) {
|
||||
Time day = (Time) msg.obj;
|
||||
mEventDialog = new CreateEventDialogFragment(day);
|
||||
mEventDialog.show(manager, TAG_EVENT_DIALOG);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public MonthByWeekFragment() {
|
||||
this(System.currentTimeMillis(), true);
|
||||
}
|
||||
|
||||
public MonthByWeekFragment(long initialTime, boolean isMiniMonth) {
|
||||
super(initialTime);
|
||||
mIsMiniMonth = isMiniMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the uri used by the loader according to the current position of
|
||||
@ -316,15 +313,6 @@ public class MonthByWeekFragment extends SimpleDayPickerFragment implements
|
||||
mAdapter.setListView(mListView);
|
||||
}
|
||||
|
||||
public MonthByWeekFragment() {
|
||||
this(System.currentTimeMillis(), true);
|
||||
}
|
||||
|
||||
public MonthByWeekFragment(long initialTime, boolean isMiniMonth) {
|
||||
super(initialTime);
|
||||
mIsMiniMonth = isMiniMonth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUpHeader() {
|
||||
if (mIsMiniMonth) {
|
||||
|
@ -44,8 +44,6 @@ import android.view.accessibility.AccessibilityManager;
|
||||
import com.android.calendar.Event;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
@ -54,6 +52,8 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class MonthWeekEventsView extends SimpleWeekView {
|
||||
|
||||
public static final String VIEW_PARAMS_ORIENTATION = "orientation";
|
||||
|
@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.calendar.month;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListFragment;
|
||||
import android.content.Context;
|
||||
@ -40,10 +37,14 @@ import android.widget.AbsListView.OnScrollListener;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This displays a titled list of weeks with selectable days. It can be
|
||||
@ -55,9 +56,8 @@ import java.util.Locale;
|
||||
*/
|
||||
public class SimpleDayPickerFragment extends ListFragment implements OnScrollListener {
|
||||
|
||||
private static final String TAG = "MonthFragment";
|
||||
private static final String KEY_CURRENT_TIME = "current_time";
|
||||
|
||||
// The number of days to display in each week
|
||||
public static final int DAYS_PER_WEEK = 7;
|
||||
// Affects when the month selection will change while scrolling up
|
||||
protected static final int SCROLL_HYST_WEEKS = 2;
|
||||
// How long the GoTo fling animation should last
|
||||
@ -65,41 +65,34 @@ public class SimpleDayPickerFragment extends ListFragment implements OnScrollLis
|
||||
// How long to wait after receiving an onScrollStateChanged notification
|
||||
// before acting on it
|
||||
protected static final int SCROLL_CHANGE_DELAY = 40;
|
||||
// The number of days to display in each week
|
||||
public static final int DAYS_PER_WEEK = 7;
|
||||
// The size of the month name displayed above the week list
|
||||
protected static final int MINI_MONTH_NAME_TEXT_SIZE = 18;
|
||||
private static final String TAG = "MonthFragment";
|
||||
private static final String KEY_CURRENT_TIME = "current_time";
|
||||
public static int LIST_TOP_OFFSET = -1; // so that the top line will be under the separator
|
||||
private static float mScale = 0;
|
||||
protected int WEEK_MIN_VISIBLE_HEIGHT = 12;
|
||||
protected int BOTTOM_BUFFER = 20;
|
||||
protected int mSaturdayColor = 0;
|
||||
protected int mSundayColor = 0;
|
||||
protected int mDayNameColor = 0;
|
||||
|
||||
// You can override these numbers to get a different appearance
|
||||
protected int mNumWeeks = 6;
|
||||
protected boolean mShowWeekNumber = false;
|
||||
protected int mDaysPerWeek = 7;
|
||||
|
||||
// These affect the scroll speed and feel
|
||||
protected float mFriction = 1.0f;
|
||||
|
||||
protected Context mContext;
|
||||
protected Handler mHandler;
|
||||
|
||||
protected float mMinimumFlingVelocity;
|
||||
|
||||
// highlighted time
|
||||
protected Time mSelectedDay = new Time();
|
||||
protected SimpleWeeksAdapter mAdapter;
|
||||
protected ListView mListView;
|
||||
protected ViewGroup mDayNamesHeader;
|
||||
protected String[] mDayLabels;
|
||||
|
||||
// disposable variable used for time calculations
|
||||
protected Time mTempTime = new Time();
|
||||
|
||||
private static float mScale = 0;
|
||||
// When the week starts; numbered like Time.<WEEKDAY> (e.g. SUNDAY=0).
|
||||
protected int mFirstDayOfWeek;
|
||||
// The first day of the focus month
|
||||
@ -141,7 +134,7 @@ public class SimpleDayPickerFragment extends ListFragment implements OnScrollLis
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable();
|
||||
// This allows us to update our position when a day is tapped
|
||||
protected DataSetObserver mObserver = new DataSetObserver() {
|
||||
@Override
|
||||
@ -578,8 +571,6 @@ public class SimpleDayPickerFragment extends ListFragment implements OnScrollLis
|
||||
mScrollStateChangedRunnable.doScrollStateChange(view, scrollState);
|
||||
}
|
||||
|
||||
protected ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable();
|
||||
|
||||
protected class ScrollStateRunnable implements Runnable {
|
||||
private int mNewState;
|
||||
|
||||
|
@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.calendar.month;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
@ -35,10 +32,14 @@ import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.HashMap;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is a dynamic view for drawing a single week. It can be configured to
|
||||
@ -48,17 +49,16 @@ import java.util.HashMap;
|
||||
* </p>
|
||||
*/
|
||||
public class SimpleWeekView extends View {
|
||||
private static final String TAG = "MonthView";
|
||||
/**
|
||||
* This sets the height of this week in pixels
|
||||
*/
|
||||
public static final String VIEW_PARAMS_HEIGHT = "height";
|
||||
|
||||
/**
|
||||
* These params can be passed into the view to control how it appears.
|
||||
* {@link #VIEW_PARAMS_WEEK} is the only required field, though the default
|
||||
* values are unlikely to fit most layouts correctly.
|
||||
*/
|
||||
/**
|
||||
* This sets the height of this week in pixels
|
||||
*/
|
||||
public static final String VIEW_PARAMS_HEIGHT = "height";
|
||||
/**
|
||||
* This specifies the position (or weeks since the epoch) of this week,
|
||||
* calculated using {@link Utils#getWeeksSinceEpochFromJulianDay}
|
||||
@ -88,15 +88,14 @@ public class SimpleWeekView extends View {
|
||||
* If this month should display week numbers. false if 0, true otherwise.
|
||||
*/
|
||||
public static final String VIEW_PARAMS_SHOW_WK_NUM = "show_wk_num";
|
||||
|
||||
protected static int DEFAULT_HEIGHT = 32;
|
||||
protected static int MIN_HEIGHT = 10;
|
||||
protected static final int DEFAULT_SELECTED_DAY = -1;
|
||||
protected static final int DEFAULT_WEEK_START = Time.SUNDAY;
|
||||
protected static final int DEFAULT_NUM_DAYS = 7;
|
||||
protected static final int DEFAULT_SHOW_WK_NUM = 0;
|
||||
protected static final int DEFAULT_FOCUS_MONTH = -1;
|
||||
|
||||
private static final String TAG = "MonthView";
|
||||
protected static int DEFAULT_HEIGHT = 32;
|
||||
protected static int MIN_HEIGHT = 10;
|
||||
protected static int DAY_SEPARATOR_WIDTH = 1;
|
||||
|
||||
protected static int MINI_DAY_NUMBER_TEXT_SIZE = 14;
|
||||
@ -166,6 +165,7 @@ public class SimpleWeekView extends View {
|
||||
protected int mDaySeparatorColor;
|
||||
protected int mTodayOutlineColor;
|
||||
protected int mWeekNumColor;
|
||||
Time mLastHoverTime = null;
|
||||
|
||||
public SimpleWeekView(Context context) {
|
||||
super(context);
|
||||
@ -547,6 +547,4 @@ public class SimpleWeekView extends View {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Time mLastHoverTime = null;
|
||||
}
|
@ -54,7 +54,6 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendarcommon2.EventRecurrence;
|
||||
import com.android.datetimepicker.date.DatePickerDialog;
|
||||
@ -64,209 +63,33 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class RecurrencePickerDialog extends DialogFragment implements OnItemSelectedListener,
|
||||
OnCheckedChangeListener, OnClickListener,
|
||||
android.widget.RadioGroup.OnCheckedChangeListener, DatePickerDialog.OnDateSetListener {
|
||||
|
||||
public static final String BUNDLE_START_TIME_MILLIS = "bundle_event_start_time";
|
||||
public static final String BUNDLE_TIME_ZONE = "bundle_event_time_zone";
|
||||
public static final String BUNDLE_RRULE = "bundle_event_rrule";
|
||||
private static final String TAG = "RecurrencePickerDialog";
|
||||
|
||||
// in dp's
|
||||
private static final int MIN_SCREEN_WIDTH_FOR_SINGLE_ROW_WEEK = 450;
|
||||
|
||||
// Update android:maxLength in EditText as needed
|
||||
private static final int INTERVAL_MAX = 99;
|
||||
private static final int INTERVAL_DEFAULT = 1;
|
||||
// Update android:maxLength in EditText as needed
|
||||
private static final int COUNT_MAX = 730;
|
||||
private static final int COUNT_DEFAULT = 5;
|
||||
|
||||
private DatePickerDialog mDatePickerDialog;
|
||||
|
||||
private class RecurrenceModel implements Parcelable {
|
||||
|
||||
// Should match EventRecurrence.DAILY, etc
|
||||
static final int FREQ_DAILY = 0;
|
||||
static final int FREQ_WEEKLY = 1;
|
||||
static final int FREQ_MONTHLY = 2;
|
||||
static final int FREQ_YEARLY = 3;
|
||||
|
||||
static final int END_NEVER = 0;
|
||||
static final int END_BY_DATE = 1;
|
||||
static final int END_BY_COUNT = 2;
|
||||
|
||||
static final int MONTHLY_BY_DATE = 0;
|
||||
static final int MONTHLY_BY_NTH_DAY_OF_WEEK = 1;
|
||||
|
||||
static final int STATE_NO_RECURRENCE = 0;
|
||||
static final int STATE_RECURRENCE = 1;
|
||||
|
||||
int recurrenceState;
|
||||
|
||||
/**
|
||||
* FREQ: Repeat pattern
|
||||
*
|
||||
* @see FREQ_DAILY
|
||||
* @see FREQ_WEEKLY
|
||||
* @see FREQ_MONTHLY
|
||||
* @see FREQ_YEARLY
|
||||
*/
|
||||
int freq = FREQ_WEEKLY;
|
||||
|
||||
/**
|
||||
* INTERVAL: Every n days/weeks/months/years. n >= 1
|
||||
*/
|
||||
int interval = INTERVAL_DEFAULT;
|
||||
|
||||
/**
|
||||
* UNTIL and COUNT: How does the the event end?
|
||||
*
|
||||
* @see END_NEVER
|
||||
* @see END_BY_DATE
|
||||
* @see END_BY_COUNT
|
||||
* @see untilDate
|
||||
* @see untilCount
|
||||
*/
|
||||
int end;
|
||||
|
||||
/**
|
||||
* UNTIL: Date of the last recurrence. Used when until == END_BY_DATE
|
||||
*/
|
||||
Time endDate;
|
||||
|
||||
/**
|
||||
* COUNT: Times to repeat. Use when until == END_BY_COUNT
|
||||
*/
|
||||
int endCount = COUNT_DEFAULT;
|
||||
|
||||
/**
|
||||
* BYDAY: Days of the week to be repeated. Sun = 0, Mon = 1, etc
|
||||
*/
|
||||
boolean[] weeklyByDayOfWeek = new boolean[7];
|
||||
|
||||
/**
|
||||
* BYDAY AND BYMONTHDAY: How to repeat monthly events? Same date of the
|
||||
* month or Same nth day of week.
|
||||
*
|
||||
* @see MONTHLY_BY_DATE
|
||||
* @see MONTHLY_BY_NTH_DAY_OF_WEEK
|
||||
*/
|
||||
int monthlyRepeat;
|
||||
|
||||
/**
|
||||
* Day of the month to repeat. Used when monthlyRepeat ==
|
||||
* MONTHLY_BY_DATE
|
||||
*/
|
||||
int monthlyByMonthDay;
|
||||
|
||||
/**
|
||||
* Day of the week to repeat. Used when monthlyRepeat ==
|
||||
* MONTHLY_BY_NTH_DAY_OF_WEEK
|
||||
*/
|
||||
int monthlyByDayOfWeek;
|
||||
|
||||
/**
|
||||
* Nth day of the week to repeat. Used when monthlyRepeat ==
|
||||
* MONTHLY_BY_NTH_DAY_OF_WEEK 0=undefined, 1=1st, 2=2nd, etc
|
||||
*/
|
||||
int monthlyByNthDayOfWeek;
|
||||
|
||||
/*
|
||||
* (generated method)
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Model [freq=" + freq + ", interval=" + interval + ", end=" + end + ", endDate="
|
||||
+ endDate + ", endCount=" + endCount + ", weeklyByDayOfWeek="
|
||||
+ Arrays.toString(weeklyByDayOfWeek) + ", monthlyRepeat=" + monthlyRepeat
|
||||
+ ", monthlyByMonthDay=" + monthlyByMonthDay + ", monthlyByDayOfWeek="
|
||||
+ monthlyByDayOfWeek + ", monthlyByNthDayOfWeek=" + monthlyByNthDayOfWeek + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public RecurrenceModel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(freq);
|
||||
dest.writeInt(interval);
|
||||
dest.writeInt(end);
|
||||
dest.writeInt(endDate.year);
|
||||
dest.writeInt(endDate.month);
|
||||
dest.writeInt(endDate.monthDay);
|
||||
dest.writeInt(endCount);
|
||||
dest.writeBooleanArray(weeklyByDayOfWeek);
|
||||
dest.writeInt(monthlyRepeat);
|
||||
dest.writeInt(monthlyByMonthDay);
|
||||
dest.writeInt(monthlyByDayOfWeek);
|
||||
dest.writeInt(monthlyByNthDayOfWeek);
|
||||
dest.writeInt(recurrenceState);
|
||||
}
|
||||
}
|
||||
|
||||
class minMaxTextWatcher implements TextWatcher {
|
||||
private int mMin;
|
||||
private int mMax;
|
||||
private int mDefault;
|
||||
|
||||
public minMaxTextWatcher(int min, int defaultInt, int max) {
|
||||
mMin = min;
|
||||
mMax = max;
|
||||
mDefault = defaultInt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
|
||||
boolean updated = false;
|
||||
int value;
|
||||
try {
|
||||
value = Integer.parseInt(s.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
value = mDefault;
|
||||
}
|
||||
|
||||
if (value < mMin) {
|
||||
value = mMin;
|
||||
updated = true;
|
||||
} else if (value > mMax) {
|
||||
updated = true;
|
||||
value = mMax;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
if (updated) {
|
||||
s.clear();
|
||||
s.append(Integer.toString(value));
|
||||
}
|
||||
|
||||
updateDoneButtonState();
|
||||
onChange(value);
|
||||
}
|
||||
|
||||
/** Override to be called after each key stroke */
|
||||
void onChange(int value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
}
|
||||
|
||||
private Resources mResources;
|
||||
private EventRecurrence mRecurrence = new EventRecurrence();
|
||||
private Time mTime = new Time(); // TODO timezone?
|
||||
private RecurrenceModel mModel = new RecurrenceModel();
|
||||
private Toast mToast;
|
||||
|
||||
private static final int[] mFreqModelToEventRecurrence = {
|
||||
EventRecurrence.DAILY,
|
||||
EventRecurrence.WEEKLY,
|
||||
EventRecurrence.MONTHLY,
|
||||
EventRecurrence.YEARLY
|
||||
};
|
||||
private static final String BUNDLE_MODEL = "bundle_model";
|
||||
private static final String BUNDLE_END_COUNT_HAS_FOCUS = "bundle_end_count_has_focus";
|
||||
private static final String FRAG_TAG_DATE_PICKER = "tag_date_picker_frag";
|
||||
private final int[] TIME_DAY_TO_CALENDAR_DAY = new int[] {
|
||||
Calendar.SUNDAY,
|
||||
Calendar.MONDAY,
|
||||
@ -276,51 +99,34 @@ public class RecurrencePickerDialog extends DialogFragment implements OnItemSele
|
||||
Calendar.FRIDAY,
|
||||
Calendar.SATURDAY,
|
||||
};
|
||||
private DatePickerDialog mDatePickerDialog;
|
||||
|
||||
// Call mStringBuilder.setLength(0) before formatting any string or else the
|
||||
// formatted text will accumulate.
|
||||
// private final StringBuilder mStringBuilder = new StringBuilder();
|
||||
// private Formatter mFormatter = new Formatter(mStringBuilder);
|
||||
|
||||
private Resources mResources;
|
||||
private EventRecurrence mRecurrence = new EventRecurrence();
|
||||
private Time mTime = new Time(); // TODO timezone?
|
||||
private RecurrenceModel mModel = new RecurrenceModel();
|
||||
private Toast mToast;
|
||||
private View mView;
|
||||
|
||||
private Spinner mFreqSpinner;
|
||||
private static final int[] mFreqModelToEventRecurrence = {
|
||||
EventRecurrence.DAILY,
|
||||
EventRecurrence.WEEKLY,
|
||||
EventRecurrence.MONTHLY,
|
||||
EventRecurrence.YEARLY
|
||||
};
|
||||
|
||||
public static final String BUNDLE_START_TIME_MILLIS = "bundle_event_start_time";
|
||||
public static final String BUNDLE_TIME_ZONE = "bundle_event_time_zone";
|
||||
public static final String BUNDLE_RRULE = "bundle_event_rrule";
|
||||
|
||||
private static final String BUNDLE_MODEL = "bundle_model";
|
||||
private static final String BUNDLE_END_COUNT_HAS_FOCUS = "bundle_end_count_has_focus";
|
||||
|
||||
private static final String FRAG_TAG_DATE_PICKER = "tag_date_picker_frag";
|
||||
|
||||
private Switch mRepeatSwitch;
|
||||
|
||||
private EditText mInterval;
|
||||
private TextView mIntervalPreText;
|
||||
private TextView mIntervalPostText;
|
||||
|
||||
private int mIntervalResId = -1;
|
||||
|
||||
private Spinner mEndSpinner;
|
||||
private TextView mEndDateTextView;
|
||||
private EditText mEndCount;
|
||||
private TextView mPostEndCount;
|
||||
private boolean mHidePostEndCount;
|
||||
|
||||
private ArrayList<CharSequence> mEndSpinnerArray = new ArrayList<CharSequence>(3);
|
||||
private EndSpinnerAdapter mEndSpinnerAdapter;
|
||||
private String mEndNeverStr;
|
||||
private String mEndDateLabel;
|
||||
private String mEndCountLabel;
|
||||
|
||||
/** Hold toggle buttons in the order per user's first day of week preference */
|
||||
private LinearLayout mWeekGroup;
|
||||
private LinearLayout mWeekGroup2;
|
||||
@ -330,15 +136,12 @@ public class RecurrencePickerDialog extends DialogFragment implements OnItemSele
|
||||
* "on every [Nth] [DAY_OF_WEEK]", e.g. "on every second Monday",
|
||||
* where [Nth] can be [first, second, third, fourth, last] */
|
||||
private String[][] mMonthRepeatByDayOfWeekStrs;
|
||||
|
||||
private LinearLayout mMonthGroup;
|
||||
private RadioGroup mMonthRepeatByRadioGroup;
|
||||
private RadioButton mRepeatMonthlyByNthDayOfWeek;
|
||||
private RadioButton mRepeatMonthlyByNthDayOfMonth;
|
||||
private String mMonthRepeatByDayOfWeekStr;
|
||||
|
||||
private Button mDone;
|
||||
|
||||
private OnRecurrenceSetListener mRecurrenceSetListener;
|
||||
|
||||
public RecurrencePickerDialog() {
|
||||
@ -1154,12 +957,193 @@ public class RecurrencePickerDialog extends DialogFragment implements OnItemSele
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnRecurrenceSetListener(OnRecurrenceSetListener l) {
|
||||
mRecurrenceSetListener = l;
|
||||
}
|
||||
|
||||
public interface OnRecurrenceSetListener {
|
||||
void onRecurrenceSet(String rrule);
|
||||
}
|
||||
|
||||
public void setOnRecurrenceSetListener(OnRecurrenceSetListener l) {
|
||||
mRecurrenceSetListener = l;
|
||||
private class RecurrenceModel implements Parcelable {
|
||||
|
||||
// Should match EventRecurrence.DAILY, etc
|
||||
static final int FREQ_DAILY = 0;
|
||||
static final int FREQ_WEEKLY = 1;
|
||||
static final int FREQ_MONTHLY = 2;
|
||||
static final int FREQ_YEARLY = 3;
|
||||
|
||||
static final int END_NEVER = 0;
|
||||
static final int END_BY_DATE = 1;
|
||||
static final int END_BY_COUNT = 2;
|
||||
|
||||
static final int MONTHLY_BY_DATE = 0;
|
||||
static final int MONTHLY_BY_NTH_DAY_OF_WEEK = 1;
|
||||
|
||||
static final int STATE_NO_RECURRENCE = 0;
|
||||
static final int STATE_RECURRENCE = 1;
|
||||
|
||||
int recurrenceState;
|
||||
|
||||
/**
|
||||
* FREQ: Repeat pattern
|
||||
*
|
||||
* @see FREQ_DAILY
|
||||
* @see FREQ_WEEKLY
|
||||
* @see FREQ_MONTHLY
|
||||
* @see FREQ_YEARLY
|
||||
*/
|
||||
int freq = FREQ_WEEKLY;
|
||||
|
||||
/**
|
||||
* INTERVAL: Every n days/weeks/months/years. n >= 1
|
||||
*/
|
||||
int interval = INTERVAL_DEFAULT;
|
||||
|
||||
/**
|
||||
* UNTIL and COUNT: How does the the event end?
|
||||
*
|
||||
* @see END_NEVER
|
||||
* @see END_BY_DATE
|
||||
* @see END_BY_COUNT
|
||||
* @see untilDate
|
||||
* @see untilCount
|
||||
*/
|
||||
int end;
|
||||
|
||||
/**
|
||||
* UNTIL: Date of the last recurrence. Used when until == END_BY_DATE
|
||||
*/
|
||||
Time endDate;
|
||||
|
||||
/**
|
||||
* COUNT: Times to repeat. Use when until == END_BY_COUNT
|
||||
*/
|
||||
int endCount = COUNT_DEFAULT;
|
||||
|
||||
/**
|
||||
* BYDAY: Days of the week to be repeated. Sun = 0, Mon = 1, etc
|
||||
*/
|
||||
boolean[] weeklyByDayOfWeek = new boolean[7];
|
||||
|
||||
/**
|
||||
* BYDAY AND BYMONTHDAY: How to repeat monthly events? Same date of the
|
||||
* month or Same nth day of week.
|
||||
*
|
||||
* @see MONTHLY_BY_DATE
|
||||
* @see MONTHLY_BY_NTH_DAY_OF_WEEK
|
||||
*/
|
||||
int monthlyRepeat;
|
||||
|
||||
/**
|
||||
* Day of the month to repeat. Used when monthlyRepeat ==
|
||||
* MONTHLY_BY_DATE
|
||||
*/
|
||||
int monthlyByMonthDay;
|
||||
|
||||
/**
|
||||
* Day of the week to repeat. Used when monthlyRepeat ==
|
||||
* MONTHLY_BY_NTH_DAY_OF_WEEK
|
||||
*/
|
||||
int monthlyByDayOfWeek;
|
||||
|
||||
/**
|
||||
* Nth day of the week to repeat. Used when monthlyRepeat ==
|
||||
* MONTHLY_BY_NTH_DAY_OF_WEEK 0=undefined, 1=1st, 2=2nd, etc
|
||||
*/
|
||||
int monthlyByNthDayOfWeek;
|
||||
|
||||
public RecurrenceModel() {
|
||||
}
|
||||
|
||||
/*
|
||||
* (generated method)
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Model [freq=" + freq + ", interval=" + interval + ", end=" + end + ", endDate="
|
||||
+ endDate + ", endCount=" + endCount + ", weeklyByDayOfWeek="
|
||||
+ Arrays.toString(weeklyByDayOfWeek) + ", monthlyRepeat=" + monthlyRepeat
|
||||
+ ", monthlyByMonthDay=" + monthlyByMonthDay + ", monthlyByDayOfWeek="
|
||||
+ monthlyByDayOfWeek + ", monthlyByNthDayOfWeek=" + monthlyByNthDayOfWeek + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(freq);
|
||||
dest.writeInt(interval);
|
||||
dest.writeInt(end);
|
||||
dest.writeInt(endDate.year);
|
||||
dest.writeInt(endDate.month);
|
||||
dest.writeInt(endDate.monthDay);
|
||||
dest.writeInt(endCount);
|
||||
dest.writeBooleanArray(weeklyByDayOfWeek);
|
||||
dest.writeInt(monthlyRepeat);
|
||||
dest.writeInt(monthlyByMonthDay);
|
||||
dest.writeInt(monthlyByDayOfWeek);
|
||||
dest.writeInt(monthlyByNthDayOfWeek);
|
||||
dest.writeInt(recurrenceState);
|
||||
}
|
||||
}
|
||||
|
||||
class minMaxTextWatcher implements TextWatcher {
|
||||
private int mMin;
|
||||
private int mMax;
|
||||
private int mDefault;
|
||||
|
||||
public minMaxTextWatcher(int min, int defaultInt, int max) {
|
||||
mMin = min;
|
||||
mMax = max;
|
||||
mDefault = defaultInt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
|
||||
boolean updated = false;
|
||||
int value;
|
||||
try {
|
||||
value = Integer.parseInt(s.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
value = mDefault;
|
||||
}
|
||||
|
||||
if (value < mMin) {
|
||||
value = mMin;
|
||||
updated = true;
|
||||
} else if (value > mMax) {
|
||||
updated = true;
|
||||
value = mMax;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
if (updated) {
|
||||
s.clear();
|
||||
s.append(Integer.toString(value));
|
||||
}
|
||||
|
||||
updateDoneButtonState();
|
||||
onChange(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to be called after each key stroke
|
||||
*/
|
||||
void onChange(int value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
}
|
||||
|
||||
private class EndSpinnerAdapter extends ArrayAdapter<CharSequence> {
|
||||
|
@ -22,9 +22,10 @@ import android.util.AttributeSet;
|
||||
import android.widget.QuickContactBadge;
|
||||
|
||||
import com.android.calendar.CalendarColorPickerDialog;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.colorpicker.ColorStateDrawable;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
/**
|
||||
* The color square used as an entry point to launching the {@link CalendarColorPickerDialog}.
|
||||
*/
|
||||
|
@ -37,37 +37,33 @@ import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.CalendarColorPickerDialog;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SelectCalendarsSimpleAdapter extends BaseAdapter implements ListAdapter,
|
||||
OnCalendarColorsLoadedListener {
|
||||
private static final String TAG = "SelectCalendarsAdapter";
|
||||
private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog";
|
||||
|
||||
private static int BOTTOM_ITEM_HEIGHT = 64;
|
||||
private static int NORMAL_ITEM_HEIGHT = 48;
|
||||
|
||||
private static final int IS_SELECTED = 1 << 0;
|
||||
private static final int IS_TOP = 1 << 1;
|
||||
private static final int IS_BOTTOM = 1 << 2;
|
||||
private static final int IS_BELOW_SELECTED = 1 << 3;
|
||||
|
||||
private CalendarColorPickerDialog mColorPickerDialog;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
private static int BOTTOM_ITEM_HEIGHT = 64;
|
||||
private static int NORMAL_ITEM_HEIGHT = 48;
|
||||
private static float mScale = 0;
|
||||
Resources mRes;
|
||||
private CalendarColorPickerDialog mColorPickerDialog;
|
||||
private LayoutInflater mInflater;
|
||||
private int mLayout;
|
||||
private int mOrientation;
|
||||
private CalendarRow[] mData;
|
||||
private Cursor mCursor;
|
||||
private int mRowCount = 0;
|
||||
|
||||
private FragmentManager mFragmentManager;
|
||||
private boolean mIsTablet;
|
||||
private int mColorViewTouchAreaIncrease;
|
||||
|
||||
private int mIdColumn;
|
||||
private int mNameColumn;
|
||||
private int mColorColumn;
|
||||
@ -75,7 +71,6 @@ public class SelectCalendarsSimpleAdapter extends BaseAdapter implements ListAda
|
||||
private int mOwnerAccountColumn;
|
||||
private int mAccountNameColumn;
|
||||
private int mAccountTypeColumn;
|
||||
private static float mScale = 0;
|
||||
private int mColorCalendarVisible;
|
||||
private int mColorCalendarHidden;
|
||||
private int mColorCalendarSecondaryVisible;
|
||||
@ -83,16 +78,6 @@ public class SelectCalendarsSimpleAdapter extends BaseAdapter implements ListAda
|
||||
|
||||
private CalendarColorCache mCache;
|
||||
|
||||
private class CalendarRow {
|
||||
long id;
|
||||
String displayName;
|
||||
String ownerAccount;
|
||||
String accountName;
|
||||
String accountType;
|
||||
int color;
|
||||
boolean selected;
|
||||
}
|
||||
|
||||
public SelectCalendarsSimpleAdapter(Context context, int layout, Cursor c, FragmentManager fm) {
|
||||
super();
|
||||
mLayout = layout;
|
||||
@ -121,56 +106,6 @@ public class SelectCalendarsSimpleAdapter extends BaseAdapter implements ListAda
|
||||
.getDimensionPixelSize(R.dimen.color_view_touch_area_increase);
|
||||
}
|
||||
|
||||
private static class TabletCalendarItemBackgrounds {
|
||||
static private int[] mBackgrounds = null;
|
||||
|
||||
/**
|
||||
* Sets up the background drawables for the calendars list
|
||||
*
|
||||
* @param res The context's resources
|
||||
*/
|
||||
static int[] getBackgrounds() {
|
||||
// Not thread safe. Ok if called only from main thread
|
||||
if (mBackgrounds != null) {
|
||||
return mBackgrounds;
|
||||
}
|
||||
|
||||
mBackgrounds = new int[16];
|
||||
|
||||
mBackgrounds[0] = R.drawable.calname_unselected;
|
||||
|
||||
mBackgrounds[IS_SELECTED] = R.drawable.calname_select_underunselected;
|
||||
|
||||
mBackgrounds[IS_SELECTED | IS_BOTTOM] =
|
||||
R.drawable.calname_bottom_select_underunselected;
|
||||
|
||||
mBackgrounds[IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED] =
|
||||
R.drawable.calname_bottom_select_underselect;
|
||||
mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[
|
||||
IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM] = mBackgrounds[IS_SELECTED | IS_BOTTOM
|
||||
| IS_BELOW_SELECTED];
|
||||
|
||||
mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED] = R.drawable.calname_select_underselect;
|
||||
mBackgrounds[IS_SELECTED | IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_SELECTED
|
||||
| IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_SELECTED | IS_TOP] = mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED];
|
||||
|
||||
mBackgrounds[IS_BOTTOM] = R.drawable.calname_bottom_unselected;
|
||||
|
||||
mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED] =
|
||||
R.drawable.calname_bottom_unselected_underselect;
|
||||
mBackgrounds[IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[IS_BOTTOM
|
||||
| IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_TOP | IS_BOTTOM] = mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED];
|
||||
|
||||
mBackgrounds[IS_BELOW_SELECTED] = R.drawable.calname_unselected_underselect;
|
||||
mBackgrounds[IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_TOP] = mBackgrounds[IS_BELOW_SELECTED];
|
||||
return mBackgrounds;
|
||||
}
|
||||
}
|
||||
|
||||
private void initData(Cursor c) {
|
||||
if (mCursor != null && c != mCursor) {
|
||||
mCursor.close();
|
||||
@ -385,4 +320,64 @@ public class SelectCalendarsSimpleAdapter extends BaseAdapter implements ListAda
|
||||
public void onCalendarColorsLoaded() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private static class TabletCalendarItemBackgrounds {
|
||||
static private int[] mBackgrounds = null;
|
||||
|
||||
/**
|
||||
* Sets up the background drawables for the calendars list
|
||||
*
|
||||
* @param res The context's resources
|
||||
*/
|
||||
static int[] getBackgrounds() {
|
||||
// Not thread safe. Ok if called only from main thread
|
||||
if (mBackgrounds != null) {
|
||||
return mBackgrounds;
|
||||
}
|
||||
|
||||
mBackgrounds = new int[16];
|
||||
|
||||
mBackgrounds[0] = R.drawable.calname_unselected;
|
||||
|
||||
mBackgrounds[IS_SELECTED] = R.drawable.calname_select_underunselected;
|
||||
|
||||
mBackgrounds[IS_SELECTED | IS_BOTTOM] =
|
||||
R.drawable.calname_bottom_select_underunselected;
|
||||
|
||||
mBackgrounds[IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED] =
|
||||
R.drawable.calname_bottom_select_underselect;
|
||||
mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[
|
||||
IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM] = mBackgrounds[IS_SELECTED | IS_BOTTOM
|
||||
| IS_BELOW_SELECTED];
|
||||
|
||||
mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED] = R.drawable.calname_select_underselect;
|
||||
mBackgrounds[IS_SELECTED | IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_SELECTED
|
||||
| IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_SELECTED | IS_TOP] = mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED];
|
||||
|
||||
mBackgrounds[IS_BOTTOM] = R.drawable.calname_bottom_unselected;
|
||||
|
||||
mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED] =
|
||||
R.drawable.calname_bottom_unselected_underselect;
|
||||
mBackgrounds[IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[IS_BOTTOM
|
||||
| IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_TOP | IS_BOTTOM] = mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED];
|
||||
|
||||
mBackgrounds[IS_BELOW_SELECTED] = R.drawable.calname_unselected_underselect;
|
||||
mBackgrounds[IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_BELOW_SELECTED];
|
||||
mBackgrounds[IS_TOP] = mBackgrounds[IS_BELOW_SELECTED];
|
||||
return mBackgrounds;
|
||||
}
|
||||
}
|
||||
|
||||
private class CalendarRow {
|
||||
long id;
|
||||
String displayName;
|
||||
String ownerAccount;
|
||||
String accountName;
|
||||
String accountType;
|
||||
int color;
|
||||
boolean selected;
|
||||
}
|
||||
}
|
||||
|
@ -36,54 +36,38 @@ import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.CalendarColorPickerDialog;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SelectCalendarsSyncAdapter extends BaseAdapter
|
||||
implements ListAdapter, AdapterView.OnItemClickListener, OnCalendarColorsLoadedListener {
|
||||
private static final String TAG = "SelCalsAdapter";
|
||||
private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog";
|
||||
|
||||
private static final int LAYOUT = R.layout.calendar_sync_item;
|
||||
private static int COLOR_CHIP_SIZE = 30;
|
||||
private final String mSyncedString;
|
||||
private final String mNotSyncedString;
|
||||
private RectShape r = new RectShape();
|
||||
|
||||
private CalendarColorPickerDialog mColorPickerDialog;
|
||||
private CalendarColorCache mCache;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
private static final int LAYOUT = R.layout.calendar_sync_item;
|
||||
private CalendarRow[] mData;
|
||||
private HashMap<Long, CalendarRow> mChanges = new HashMap<Long, CalendarRow>();
|
||||
private int mRowCount = 0;
|
||||
|
||||
private int mIdColumn;
|
||||
private int mNameColumn;
|
||||
private int mColorColumn;
|
||||
private int mSyncedColumn;
|
||||
private int mAccountNameColumn;
|
||||
private int mAccountTypeColumn;
|
||||
|
||||
private boolean mIsTablet;
|
||||
private FragmentManager mFragmentManager;
|
||||
private int mColorViewTouchAreaIncrease;
|
||||
|
||||
|
||||
private final String mSyncedString;
|
||||
private final String mNotSyncedString;
|
||||
|
||||
public class CalendarRow {
|
||||
long id;
|
||||
String displayName;
|
||||
int color;
|
||||
boolean synced;
|
||||
boolean originalSynced;
|
||||
String accountName;
|
||||
String accountType;
|
||||
}
|
||||
|
||||
public SelectCalendarsSyncAdapter(Context context, Cursor c, FragmentManager manager) {
|
||||
super();
|
||||
initData(c);
|
||||
@ -102,6 +86,14 @@ public class SelectCalendarsSyncAdapter extends BaseAdapter
|
||||
mNotSyncedString = res.getString(R.string.not_synced);
|
||||
}
|
||||
|
||||
private static void setText(View view, int id, String text) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return;
|
||||
}
|
||||
TextView textView = (TextView) view.findViewById(id);
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
private void initData(Cursor c) {
|
||||
if (c == null) {
|
||||
mRowCount = 0;
|
||||
@ -217,14 +209,6 @@ public class SelectCalendarsSyncAdapter extends BaseAdapter
|
||||
return mCache.hasColors(mData[position].accountName, mData[position].accountType);
|
||||
}
|
||||
|
||||
private static void setText(View view, int id, String text) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return;
|
||||
}
|
||||
TextView textView = (TextView) view.findViewById(id);
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mRowCount;
|
||||
@ -285,4 +269,14 @@ public class SelectCalendarsSyncAdapter extends BaseAdapter
|
||||
public void onCalendarColorsLoaded() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public class CalendarRow {
|
||||
long id;
|
||||
String displayName;
|
||||
int color;
|
||||
boolean synced;
|
||||
boolean originalSynced;
|
||||
String accountName;
|
||||
String accountType;
|
||||
}
|
||||
}
|
||||
|
@ -42,12 +42,13 @@ import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.AsyncQueryService;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.selectcalendars.SelectCalendarsSyncAdapter.CalendarRow;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SelectCalendarsSyncFragment extends ListFragment
|
||||
implements View.OnClickListener, LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
@ -69,11 +70,10 @@ public class SelectCalendarsSyncFragment extends ListFragment
|
||||
Calendars.ACCOUNT_NAME,
|
||||
Calendars.ACCOUNT_TYPE,
|
||||
"(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY, };
|
||||
|
||||
private final String[] mArgs = new String[2];
|
||||
private TextView mSyncStatus;
|
||||
private Button mAccountsButton;
|
||||
private Account mAccount;
|
||||
private final String[] mArgs = new String[2];
|
||||
private AsyncQueryService mService;
|
||||
private Handler mHandler = new Handler();
|
||||
private ContentObserver mCalendarsObserver = new ContentObserver(mHandler) {
|
||||
|
@ -28,18 +28,16 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ExpandableListView;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SelectSyncedCalendarsMultiAccountActivity extends ExpandableListActivity
|
||||
implements View.OnClickListener {
|
||||
|
||||
private static final String TAG = "Calendar";
|
||||
private static final String EXPANDED_KEY = "is_expanded";
|
||||
private static final String ACCOUNT_UNIQUE_KEY = "ACCOUNT_KEY";
|
||||
private MatrixCursor mAccountsCursor = null;
|
||||
private ExpandableListView mList;
|
||||
private SelectSyncedCalendarsMultiAccountAdapter mAdapter;
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
Calendars._ID,
|
||||
Calendars.ACCOUNT_TYPE,
|
||||
@ -47,6 +45,9 @@ public class SelectSyncedCalendarsMultiAccountActivity extends ExpandableListAct
|
||||
Calendars.ACCOUNT_TYPE + " || " + Calendars.ACCOUNT_NAME + " AS " +
|
||||
ACCOUNT_UNIQUE_KEY,
|
||||
};
|
||||
private MatrixCursor mAccountsCursor = null;
|
||||
private ExpandableListView mList;
|
||||
private SelectSyncedCalendarsMultiAccountAdapter mAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
|
@ -42,7 +42,6 @@ import android.widget.CursorTreeAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.calendar.CalendarColorPickerDialog;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
|
||||
|
||||
@ -50,6 +49,8 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter implements
|
||||
View.OnClickListener, OnCalendarColorsLoadedListener {
|
||||
|
||||
@ -61,56 +62,13 @@ public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter
|
||||
+ Calendars.CALENDAR_DISPLAY_NAME + " COLLATE NOCASE";
|
||||
private static final String ACCOUNT_SELECTION = Calendars.ACCOUNT_NAME + "=?"
|
||||
+ " AND " + Calendars.ACCOUNT_TYPE + "=?";
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final ContentResolver mResolver;
|
||||
private final SelectSyncedCalendarsMultiAccountActivity mActivity;
|
||||
private final FragmentManager mFragmentManager;
|
||||
private final boolean mIsTablet;
|
||||
private CalendarColorPickerDialog mColorPickerDialog;
|
||||
private final View mView;
|
||||
private final static Runnable mStopRefreshing = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mRefresh = false;
|
||||
}
|
||||
};
|
||||
private Map<String, AuthenticatorDescription> mTypeToAuthDescription
|
||||
= new HashMap<String, AuthenticatorDescription>();
|
||||
protected AuthenticatorDescription[] mAuthDescs;
|
||||
|
||||
// These track changes to the synced state of calendars
|
||||
private Map<Long, Boolean> mCalendarChanges
|
||||
= new HashMap<Long, Boolean>();
|
||||
private Map<Long, Boolean> mCalendarInitialStates
|
||||
= new HashMap<Long, Boolean>();
|
||||
|
||||
// Flag for when the cursors have all been closed to ensure no race condition with queries.
|
||||
private boolean mClosedCursorsFlag;
|
||||
|
||||
// This is for keeping MatrixCursor copies so that we can requery in the background.
|
||||
private Map<String, Cursor> mChildrenCursors
|
||||
= new HashMap<String, Cursor>();
|
||||
|
||||
private AsyncCalendarsUpdater mCalendarsUpdater;
|
||||
// This is to keep our update tokens separate from other tokens. Since we cancel old updates
|
||||
// when a new update comes in, we'd like to leave a token space that won't be canceled.
|
||||
private static final int MIN_UPDATE_TOKEN = 1000;
|
||||
private static int mUpdateToken = MIN_UPDATE_TOKEN;
|
||||
// How long to wait between requeries of the calendars to see if anything has changed.
|
||||
private static final int REFRESH_DELAY = 5000;
|
||||
// How long to keep refreshing for
|
||||
private static final int REFRESH_DURATION = 60000;
|
||||
private static boolean mRefresh = true;
|
||||
|
||||
private static String mSyncedText;
|
||||
private static String mNotSyncedText;
|
||||
|
||||
// This is to keep track of whether or not multiple calendars have the same display name
|
||||
private static HashMap<String, Boolean> mIsDuplicateName = new HashMap<String, Boolean>();
|
||||
|
||||
private int mColorViewTouchAreaIncrease;
|
||||
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
Calendars._ID,
|
||||
Calendars.ACCOUNT_NAME,
|
||||
@ -132,91 +90,46 @@ public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter
|
||||
private static final int SYNCED_COLUMN = 6;
|
||||
private static final int PRIMARY_COLUMN = 7;
|
||||
private static final int ACCOUNT_TYPE_COLUMN = 8;
|
||||
|
||||
private static final int TAG_ID_CALENDAR_ID = R.id.calendar;
|
||||
private static final int TAG_ID_SYNC_CHECKBOX = R.id.sync;
|
||||
|
||||
private static int mUpdateToken = MIN_UPDATE_TOKEN;
|
||||
private static boolean mRefresh = true;
|
||||
private final static Runnable mStopRefreshing = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mRefresh = false;
|
||||
}
|
||||
};
|
||||
private static String mSyncedText;
|
||||
private static String mNotSyncedText;
|
||||
// This is to keep track of whether or not multiple calendars have the same display name
|
||||
private static HashMap<String, Boolean> mIsDuplicateName = new HashMap<String, Boolean>();
|
||||
private final LayoutInflater mInflater;
|
||||
private final ContentResolver mResolver;
|
||||
private final SelectSyncedCalendarsMultiAccountActivity mActivity;
|
||||
private final FragmentManager mFragmentManager;
|
||||
private final boolean mIsTablet;
|
||||
private final View mView;
|
||||
protected AuthenticatorDescription[] mAuthDescs;
|
||||
private CalendarColorPickerDialog mColorPickerDialog;
|
||||
private Map<String, AuthenticatorDescription> mTypeToAuthDescription
|
||||
= new HashMap<String, AuthenticatorDescription>();
|
||||
// These track changes to the synced state of calendars
|
||||
private Map<Long, Boolean> mCalendarChanges
|
||||
= new HashMap<Long, Boolean>();
|
||||
private Map<Long, Boolean> mCalendarInitialStates
|
||||
= new HashMap<Long, Boolean>();
|
||||
// Flag for when the cursors have all been closed to ensure no race condition with queries.
|
||||
private boolean mClosedCursorsFlag;
|
||||
// This is for keeping MatrixCursor copies so that we can requery in the background.
|
||||
private Map<String, Cursor> mChildrenCursors
|
||||
= new HashMap<String, Cursor>();
|
||||
private AsyncCalendarsUpdater mCalendarsUpdater;
|
||||
private int mColorViewTouchAreaIncrease;
|
||||
private CalendarColorCache mCache;
|
||||
|
||||
private class AsyncCalendarsUpdater extends AsyncQueryHandler {
|
||||
|
||||
public AsyncCalendarsUpdater(ContentResolver cr) {
|
||||
super(cr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
if(cursor == null) {
|
||||
return;
|
||||
}
|
||||
synchronized(mChildrenCursors) {
|
||||
if (mClosedCursorsFlag || (mActivity != null && mActivity.isFinishing())) {
|
||||
cursor.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Cursor currentCursor = mChildrenCursors.get(cookie);
|
||||
// Check if the new cursor has the same content as our old cursor
|
||||
if (currentCursor != null) {
|
||||
if (Utils.compareCursors(currentCursor, cursor)) {
|
||||
cursor.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If not then make a new matrix cursor for our Map
|
||||
MatrixCursor newCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
cursor.close();
|
||||
// And update our list of duplicated names
|
||||
Utils.checkForDuplicateNames(mIsDuplicateName, newCursor, NAME_COLUMN);
|
||||
|
||||
mChildrenCursors.put((String)cookie, newCursor);
|
||||
try {
|
||||
setChildrenCursor(token, newCursor);
|
||||
} catch (NullPointerException e) {
|
||||
Log.w(TAG, "Adapter expired, try again on the next query: " + e);
|
||||
}
|
||||
// Clean up our old cursor if we had one. We have to do this after setting the new
|
||||
// cursor so that our view doesn't throw on an invalid cursor.
|
||||
if (currentCursor != null) {
|
||||
currentCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for changing the sync state when a calendar's button is pressed.
|
||||
*
|
||||
* This gets called when the CheckBox for a calendar is clicked. It toggles
|
||||
* the sync state for the associated calendar and saves a change of state to
|
||||
* a hashmap. It also compares against the original value and removes any
|
||||
* changes from the hashmap if this is back at its initial state.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
long id = (Long) v.getTag(TAG_ID_CALENDAR_ID);
|
||||
boolean newState;
|
||||
boolean initialState = mCalendarInitialStates.get(id);
|
||||
if (mCalendarChanges.containsKey(id)) {
|
||||
// Negate to reflect the click
|
||||
newState = !mCalendarChanges.get(id);
|
||||
} else {
|
||||
// Negate to reflect the click
|
||||
newState = !initialState;
|
||||
}
|
||||
|
||||
if (newState == initialState) {
|
||||
mCalendarChanges.remove(id);
|
||||
} else {
|
||||
mCalendarChanges.put(id, newState);
|
||||
}
|
||||
|
||||
((CheckBox) v.getTag(TAG_ID_SYNC_CHECKBOX)).setChecked(newState);
|
||||
setText(v, R.id.status, newState ? mSyncedText : mNotSyncedText);
|
||||
}
|
||||
|
||||
public SelectSyncedCalendarsMultiAccountAdapter(Context context, Cursor acctsCursor,
|
||||
SelectSyncedCalendarsMultiAccountActivity act) {
|
||||
SelectSyncedCalendarsMultiAccountActivity act) {
|
||||
super(acctsCursor, context);
|
||||
mSyncedText = context.getString(R.string.synced);
|
||||
mNotSyncedText = context.getString(R.string.not_synced);
|
||||
@ -251,6 +164,45 @@ public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter
|
||||
.getDimensionPixelSize(R.dimen.color_view_touch_area_increase);
|
||||
}
|
||||
|
||||
private static void setText(View view, int id, String text) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return;
|
||||
}
|
||||
TextView textView = (TextView) view.findViewById(id);
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for changing the sync state when a calendar's button is pressed.
|
||||
*
|
||||
* This gets called when the CheckBox for a calendar is clicked. It toggles
|
||||
* the sync state for the associated calendar and saves a change of state to
|
||||
* a hashmap. It also compares against the original value and removes any
|
||||
* changes from the hashmap if this is back at its initial state.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
long id = (Long) v.getTag(TAG_ID_CALENDAR_ID);
|
||||
boolean newState;
|
||||
boolean initialState = mCalendarInitialStates.get(id);
|
||||
if (mCalendarChanges.containsKey(id)) {
|
||||
// Negate to reflect the click
|
||||
newState = !mCalendarChanges.get(id);
|
||||
} else {
|
||||
// Negate to reflect the click
|
||||
newState = !initialState;
|
||||
}
|
||||
|
||||
if (newState == initialState) {
|
||||
mCalendarChanges.remove(id);
|
||||
} else {
|
||||
mCalendarChanges.put(id, newState);
|
||||
}
|
||||
|
||||
((CheckBox) v.getTag(TAG_ID_SYNC_CHECKBOX)).setChecked(newState);
|
||||
setText(v, R.id.status, newState ? mSyncedText : mNotSyncedText);
|
||||
}
|
||||
|
||||
public void startRefreshStopDelay() {
|
||||
mRefresh = true;
|
||||
mView.postDelayed(mStopRefreshing, REFRESH_DURATION);
|
||||
@ -287,14 +239,6 @@ public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private static void setText(View view, int id, String text) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return;
|
||||
}
|
||||
TextView textView = (TextView) view.findViewById(id);
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the label associated with a particular account type. If none found, return null.
|
||||
* @param accountType the type of account
|
||||
@ -434,6 +378,57 @@ public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalendarColorsLoaded() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private class AsyncCalendarsUpdater extends AsyncQueryHandler {
|
||||
|
||||
public AsyncCalendarsUpdater(ContentResolver cr) {
|
||||
super(cr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
if (cursor == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (mChildrenCursors) {
|
||||
if (mClosedCursorsFlag || (mActivity != null && mActivity.isFinishing())) {
|
||||
cursor.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Cursor currentCursor = mChildrenCursors.get(cookie);
|
||||
// Check if the new cursor has the same content as our old cursor
|
||||
if (currentCursor != null) {
|
||||
if (Utils.compareCursors(currentCursor, cursor)) {
|
||||
cursor.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If not then make a new matrix cursor for our Map
|
||||
MatrixCursor newCursor = Utils.matrixCursorFromCursor(cursor);
|
||||
cursor.close();
|
||||
// And update our list of duplicated names
|
||||
Utils.checkForDuplicateNames(mIsDuplicateName, newCursor, NAME_COLUMN);
|
||||
|
||||
mChildrenCursors.put((String) cookie, newCursor);
|
||||
try {
|
||||
setChildrenCursor(token, newCursor);
|
||||
} catch (NullPointerException e) {
|
||||
Log.w(TAG, "Adapter expired, try again on the next query: " + e);
|
||||
}
|
||||
// Clean up our old cursor if we had one. We have to do this after setting the new
|
||||
// cursor so that our view doesn't throw on an invalid cursor.
|
||||
if (currentCursor != null) {
|
||||
currentCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RefreshCalendars implements Runnable {
|
||||
|
||||
int mToken;
|
||||
@ -462,9 +457,4 @@ public class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter
|
||||
CALENDARS_ORDERBY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalendarColorsLoaded() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import com.android.calendar.CalendarController.EventType;
|
||||
import com.android.calendar.CalendarController.ViewType;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SelectVisibleCalendarsActivity extends AbstractCalendarActivity {
|
||||
private SelectVisibleCalendarsFragment mFragment;
|
||||
|
@ -34,10 +34,11 @@ import com.android.calendar.AsyncQueryService;
|
||||
import com.android.calendar.CalendarController;
|
||||
import com.android.calendar.CalendarController.EventInfo;
|
||||
import com.android.calendar.CalendarController.EventType;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
public class SelectVisibleCalendarsFragment extends Fragment
|
||||
implements AdapterView.OnItemClickListener, CalendarController.EventHandler,
|
||||
OnCalendarColorsLoadedListener {
|
||||
|
@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.calendar.widget;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
@ -28,17 +25,208 @@ import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
class CalendarAppWidgetModel {
|
||||
private static final String TAG = CalendarAppWidgetModel.class.getSimpleName();
|
||||
private static final boolean LOGD = false;
|
||||
|
||||
final List<RowInfo> mRowInfos;
|
||||
final List<EventInfo> mEventInfos;
|
||||
final List<DayInfo> mDayInfos;
|
||||
final Context mContext;
|
||||
final long mNow;
|
||||
final int mTodayJulianDay;
|
||||
final int mMaxJulianDay;
|
||||
private String mHomeTZName;
|
||||
private boolean mShowTZ;
|
||||
|
||||
public CalendarAppWidgetModel(Context context, String timeZone) {
|
||||
mNow = System.currentTimeMillis();
|
||||
Time time = new Time(timeZone);
|
||||
time.setToNow(); // This is needed for gmtoff to be set
|
||||
mTodayJulianDay = Time.getJulianDay(mNow, time.gmtoff);
|
||||
mMaxJulianDay = mTodayJulianDay + CalendarAppWidgetService.MAX_DAYS - 1;
|
||||
mEventInfos = new ArrayList<EventInfo>(50);
|
||||
mRowInfos = new ArrayList<RowInfo>(50);
|
||||
mDayInfos = new ArrayList<DayInfo>(8);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void buildFromCursor(Cursor cursor, String timeZone) {
|
||||
final Time recycle = new Time(timeZone);
|
||||
final ArrayList<LinkedList<RowInfo>> mBuckets =
|
||||
new ArrayList<LinkedList<RowInfo>>(CalendarAppWidgetService.MAX_DAYS);
|
||||
for (int i = 0; i < CalendarAppWidgetService.MAX_DAYS; i++) {
|
||||
mBuckets.add(new LinkedList<RowInfo>());
|
||||
}
|
||||
recycle.setToNow();
|
||||
mShowTZ = !TextUtils.equals(timeZone, Time.getCurrentTimezone());
|
||||
if (mShowTZ) {
|
||||
mHomeTZName = TimeZone.getTimeZone(timeZone).getDisplayName(recycle.isDst != 0,
|
||||
TimeZone.SHORT);
|
||||
}
|
||||
|
||||
cursor.moveToPosition(-1);
|
||||
String tz = Utils.getTimeZone(mContext, null);
|
||||
while (cursor.moveToNext()) {
|
||||
final int rowId = cursor.getPosition();
|
||||
final long eventId = cursor.getLong(CalendarAppWidgetService.INDEX_EVENT_ID);
|
||||
final boolean allDay = cursor.getInt(CalendarAppWidgetService.INDEX_ALL_DAY) != 0;
|
||||
long start = cursor.getLong(CalendarAppWidgetService.INDEX_BEGIN);
|
||||
long end = cursor.getLong(CalendarAppWidgetService.INDEX_END);
|
||||
final String title = cursor.getString(CalendarAppWidgetService.INDEX_TITLE);
|
||||
final String location =
|
||||
cursor.getString(CalendarAppWidgetService.INDEX_EVENT_LOCATION);
|
||||
// we don't compute these ourselves because it seems to produce the
|
||||
// wrong endDay for all day events
|
||||
final int startDay = cursor.getInt(CalendarAppWidgetService.INDEX_START_DAY);
|
||||
final int endDay = cursor.getInt(CalendarAppWidgetService.INDEX_END_DAY);
|
||||
final int color = cursor.getInt(CalendarAppWidgetService.INDEX_COLOR);
|
||||
final int selfStatus = cursor
|
||||
.getInt(CalendarAppWidgetService.INDEX_SELF_ATTENDEE_STATUS);
|
||||
|
||||
// Adjust all-day times into local timezone
|
||||
if (allDay) {
|
||||
start = Utils.convertAlldayUtcToLocal(recycle, start, tz);
|
||||
end = Utils.convertAlldayUtcToLocal(recycle, end, tz);
|
||||
}
|
||||
|
||||
if (LOGD) {
|
||||
Log.d(TAG, "Row #" + rowId + " allDay:" + allDay + " start:" + start
|
||||
+ " end:" + end + " eventId:" + eventId);
|
||||
}
|
||||
|
||||
// we might get some extra events when querying, in order to
|
||||
// deal with all-day events
|
||||
if (end < mNow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int i = mEventInfos.size();
|
||||
mEventInfos.add(populateEventInfo(eventId, allDay, start, end, startDay, endDay, title,
|
||||
location, color, selfStatus));
|
||||
// populate the day buckets that this event falls into
|
||||
int from = Math.max(startDay, mTodayJulianDay);
|
||||
int to = Math.min(endDay, mMaxJulianDay);
|
||||
for (int day = from; day <= to; day++) {
|
||||
LinkedList<RowInfo> bucket = mBuckets.get(day - mTodayJulianDay);
|
||||
RowInfo rowInfo = new RowInfo(RowInfo.TYPE_MEETING, i);
|
||||
if (allDay) {
|
||||
bucket.addFirst(rowInfo);
|
||||
} else {
|
||||
bucket.add(rowInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int day = mTodayJulianDay;
|
||||
int count = 0;
|
||||
for (LinkedList<RowInfo> bucket : mBuckets) {
|
||||
if (!bucket.isEmpty()) {
|
||||
// We don't show day header in today
|
||||
if (day != mTodayJulianDay) {
|
||||
final DayInfo dayInfo = populateDayInfo(day, recycle);
|
||||
// Add the day header
|
||||
final int dayIndex = mDayInfos.size();
|
||||
mDayInfos.add(dayInfo);
|
||||
mRowInfos.add(new RowInfo(RowInfo.TYPE_DAY, dayIndex));
|
||||
}
|
||||
|
||||
// Add the event row infos
|
||||
mRowInfos.addAll(bucket);
|
||||
count += bucket.size();
|
||||
}
|
||||
day++;
|
||||
if (count >= CalendarAppWidgetService.EVENT_MIN_COUNT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EventInfo populateEventInfo(long eventId, boolean allDay, long start, long end,
|
||||
int startDay, int endDay, String title, String location, int color, int selfStatus) {
|
||||
EventInfo eventInfo = new EventInfo();
|
||||
|
||||
// Compute a human-readable string for the start time of the event
|
||||
StringBuilder whenString = new StringBuilder();
|
||||
int visibWhen;
|
||||
int flags = DateUtils.FORMAT_ABBREV_ALL;
|
||||
visibWhen = View.VISIBLE;
|
||||
if (allDay) {
|
||||
flags |= DateUtils.FORMAT_SHOW_DATE;
|
||||
whenString.append(Utils.formatDateRange(mContext, start, end, flags));
|
||||
} else {
|
||||
flags |= DateUtils.FORMAT_SHOW_TIME;
|
||||
if (DateFormat.is24HourFormat(mContext)) {
|
||||
flags |= DateUtils.FORMAT_24HOUR;
|
||||
}
|
||||
if (endDay > startDay) {
|
||||
flags |= DateUtils.FORMAT_SHOW_DATE;
|
||||
}
|
||||
whenString.append(Utils.formatDateRange(mContext, start, end, flags));
|
||||
|
||||
if (mShowTZ) {
|
||||
whenString.append(" ").append(mHomeTZName);
|
||||
}
|
||||
}
|
||||
eventInfo.id = eventId;
|
||||
eventInfo.start = start;
|
||||
eventInfo.end = end;
|
||||
eventInfo.allDay = allDay;
|
||||
eventInfo.when = whenString.toString();
|
||||
eventInfo.visibWhen = visibWhen;
|
||||
eventInfo.color = color;
|
||||
eventInfo.selfAttendeeStatus = selfStatus;
|
||||
|
||||
// What
|
||||
if (TextUtils.isEmpty(title)) {
|
||||
eventInfo.title = mContext.getString(R.string.no_title_label);
|
||||
} else {
|
||||
eventInfo.title = title;
|
||||
}
|
||||
eventInfo.visibTitle = View.VISIBLE;
|
||||
|
||||
// Where
|
||||
if (!TextUtils.isEmpty(location)) {
|
||||
eventInfo.visibWhere = View.VISIBLE;
|
||||
eventInfo.where = location;
|
||||
} else {
|
||||
eventInfo.visibWhere = View.GONE;
|
||||
}
|
||||
return eventInfo;
|
||||
}
|
||||
|
||||
private DayInfo populateDayInfo(int julianDay, Time recycle) {
|
||||
long millis = recycle.setJulianDay(julianDay);
|
||||
int flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE;
|
||||
|
||||
String label;
|
||||
if (julianDay == mTodayJulianDay + 1) {
|
||||
label = mContext.getString(R.string.agenda_tomorrow,
|
||||
Utils.formatDateRange(mContext, millis, millis, flags).toString());
|
||||
} else {
|
||||
flags |= DateUtils.FORMAT_SHOW_WEEKDAY;
|
||||
label = Utils.formatDateRange(mContext, millis, millis, flags);
|
||||
}
|
||||
return new DayInfo(julianDay, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("\nCalendarAppWidgetModel [eventInfos=");
|
||||
builder.append(mEventInfos);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link RowInfo} is a class that represents a single row in the widget. It
|
||||
* is actually only a pointer to either a {@link DayInfo} or an
|
||||
@ -50,7 +238,7 @@ class CalendarAppWidgetModel {
|
||||
static final int TYPE_MEETING = 1;
|
||||
|
||||
/**
|
||||
* mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING)
|
||||
* mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING)
|
||||
*/
|
||||
final int mType;
|
||||
|
||||
@ -194,10 +382,14 @@ class CalendarAppWidgetModel {
|
||||
*/
|
||||
static class DayInfo {
|
||||
|
||||
/** The Julian day */
|
||||
/**
|
||||
* The Julian day
|
||||
*/
|
||||
final int mJulianDay;
|
||||
|
||||
/** The string representation of this day header, to be displayed */
|
||||
/**
|
||||
* The string representation of this day header, to be displayed
|
||||
*/
|
||||
final String mDayLabel;
|
||||
|
||||
DayInfo(int julianDay, String label) {
|
||||
@ -239,192 +431,4 @@ class CalendarAppWidgetModel {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final List<RowInfo> mRowInfos;
|
||||
final List<EventInfo> mEventInfos;
|
||||
final List<DayInfo> mDayInfos;
|
||||
final Context mContext;
|
||||
final long mNow;
|
||||
final int mTodayJulianDay;
|
||||
final int mMaxJulianDay;
|
||||
|
||||
public CalendarAppWidgetModel(Context context, String timeZone) {
|
||||
mNow = System.currentTimeMillis();
|
||||
Time time = new Time(timeZone);
|
||||
time.setToNow(); // This is needed for gmtoff to be set
|
||||
mTodayJulianDay = Time.getJulianDay(mNow, time.gmtoff);
|
||||
mMaxJulianDay = mTodayJulianDay + CalendarAppWidgetService.MAX_DAYS - 1;
|
||||
mEventInfos = new ArrayList<EventInfo>(50);
|
||||
mRowInfos = new ArrayList<RowInfo>(50);
|
||||
mDayInfos = new ArrayList<DayInfo>(8);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void buildFromCursor(Cursor cursor, String timeZone) {
|
||||
final Time recycle = new Time(timeZone);
|
||||
final ArrayList<LinkedList<RowInfo>> mBuckets =
|
||||
new ArrayList<LinkedList<RowInfo>>(CalendarAppWidgetService.MAX_DAYS);
|
||||
for (int i = 0; i < CalendarAppWidgetService.MAX_DAYS; i++) {
|
||||
mBuckets.add(new LinkedList<RowInfo>());
|
||||
}
|
||||
recycle.setToNow();
|
||||
mShowTZ = !TextUtils.equals(timeZone, Time.getCurrentTimezone());
|
||||
if (mShowTZ) {
|
||||
mHomeTZName = TimeZone.getTimeZone(timeZone).getDisplayName(recycle.isDst != 0,
|
||||
TimeZone.SHORT);
|
||||
}
|
||||
|
||||
cursor.moveToPosition(-1);
|
||||
String tz = Utils.getTimeZone(mContext, null);
|
||||
while (cursor.moveToNext()) {
|
||||
final int rowId = cursor.getPosition();
|
||||
final long eventId = cursor.getLong(CalendarAppWidgetService.INDEX_EVENT_ID);
|
||||
final boolean allDay = cursor.getInt(CalendarAppWidgetService.INDEX_ALL_DAY) != 0;
|
||||
long start = cursor.getLong(CalendarAppWidgetService.INDEX_BEGIN);
|
||||
long end = cursor.getLong(CalendarAppWidgetService.INDEX_END);
|
||||
final String title = cursor.getString(CalendarAppWidgetService.INDEX_TITLE);
|
||||
final String location =
|
||||
cursor.getString(CalendarAppWidgetService.INDEX_EVENT_LOCATION);
|
||||
// we don't compute these ourselves because it seems to produce the
|
||||
// wrong endDay for all day events
|
||||
final int startDay = cursor.getInt(CalendarAppWidgetService.INDEX_START_DAY);
|
||||
final int endDay = cursor.getInt(CalendarAppWidgetService.INDEX_END_DAY);
|
||||
final int color = cursor.getInt(CalendarAppWidgetService.INDEX_COLOR);
|
||||
final int selfStatus = cursor
|
||||
.getInt(CalendarAppWidgetService.INDEX_SELF_ATTENDEE_STATUS);
|
||||
|
||||
// Adjust all-day times into local timezone
|
||||
if (allDay) {
|
||||
start = Utils.convertAlldayUtcToLocal(recycle, start, tz);
|
||||
end = Utils.convertAlldayUtcToLocal(recycle, end, tz);
|
||||
}
|
||||
|
||||
if (LOGD) {
|
||||
Log.d(TAG, "Row #" + rowId + " allDay:" + allDay + " start:" + start
|
||||
+ " end:" + end + " eventId:" + eventId);
|
||||
}
|
||||
|
||||
// we might get some extra events when querying, in order to
|
||||
// deal with all-day events
|
||||
if (end < mNow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int i = mEventInfos.size();
|
||||
mEventInfos.add(populateEventInfo(eventId, allDay, start, end, startDay, endDay, title,
|
||||
location, color, selfStatus));
|
||||
// populate the day buckets that this event falls into
|
||||
int from = Math.max(startDay, mTodayJulianDay);
|
||||
int to = Math.min(endDay, mMaxJulianDay);
|
||||
for (int day = from; day <= to; day++) {
|
||||
LinkedList<RowInfo> bucket = mBuckets.get(day - mTodayJulianDay);
|
||||
RowInfo rowInfo = new RowInfo(RowInfo.TYPE_MEETING, i);
|
||||
if (allDay) {
|
||||
bucket.addFirst(rowInfo);
|
||||
} else {
|
||||
bucket.add(rowInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int day = mTodayJulianDay;
|
||||
int count = 0;
|
||||
for (LinkedList<RowInfo> bucket : mBuckets) {
|
||||
if (!bucket.isEmpty()) {
|
||||
// We don't show day header in today
|
||||
if (day != mTodayJulianDay) {
|
||||
final DayInfo dayInfo = populateDayInfo(day, recycle);
|
||||
// Add the day header
|
||||
final int dayIndex = mDayInfos.size();
|
||||
mDayInfos.add(dayInfo);
|
||||
mRowInfos.add(new RowInfo(RowInfo.TYPE_DAY, dayIndex));
|
||||
}
|
||||
|
||||
// Add the event row infos
|
||||
mRowInfos.addAll(bucket);
|
||||
count += bucket.size();
|
||||
}
|
||||
day++;
|
||||
if (count >= CalendarAppWidgetService.EVENT_MIN_COUNT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EventInfo populateEventInfo(long eventId, boolean allDay, long start, long end,
|
||||
int startDay, int endDay, String title, String location, int color, int selfStatus) {
|
||||
EventInfo eventInfo = new EventInfo();
|
||||
|
||||
// Compute a human-readable string for the start time of the event
|
||||
StringBuilder whenString = new StringBuilder();
|
||||
int visibWhen;
|
||||
int flags = DateUtils.FORMAT_ABBREV_ALL;
|
||||
visibWhen = View.VISIBLE;
|
||||
if (allDay) {
|
||||
flags |= DateUtils.FORMAT_SHOW_DATE;
|
||||
whenString.append(Utils.formatDateRange(mContext, start, end, flags));
|
||||
} else {
|
||||
flags |= DateUtils.FORMAT_SHOW_TIME;
|
||||
if (DateFormat.is24HourFormat(mContext)) {
|
||||
flags |= DateUtils.FORMAT_24HOUR;
|
||||
}
|
||||
if (endDay > startDay) {
|
||||
flags |= DateUtils.FORMAT_SHOW_DATE;
|
||||
}
|
||||
whenString.append(Utils.formatDateRange(mContext, start, end, flags));
|
||||
|
||||
if (mShowTZ) {
|
||||
whenString.append(" ").append(mHomeTZName);
|
||||
}
|
||||
}
|
||||
eventInfo.id = eventId;
|
||||
eventInfo.start = start;
|
||||
eventInfo.end = end;
|
||||
eventInfo.allDay = allDay;
|
||||
eventInfo.when = whenString.toString();
|
||||
eventInfo.visibWhen = visibWhen;
|
||||
eventInfo.color = color;
|
||||
eventInfo.selfAttendeeStatus = selfStatus;
|
||||
|
||||
// What
|
||||
if (TextUtils.isEmpty(title)) {
|
||||
eventInfo.title = mContext.getString(R.string.no_title_label);
|
||||
} else {
|
||||
eventInfo.title = title;
|
||||
}
|
||||
eventInfo.visibTitle = View.VISIBLE;
|
||||
|
||||
// Where
|
||||
if (!TextUtils.isEmpty(location)) {
|
||||
eventInfo.visibWhere = View.VISIBLE;
|
||||
eventInfo.where = location;
|
||||
} else {
|
||||
eventInfo.visibWhere = View.GONE;
|
||||
}
|
||||
return eventInfo;
|
||||
}
|
||||
|
||||
private DayInfo populateDayInfo(int julianDay, Time recycle) {
|
||||
long millis = recycle.setJulianDay(julianDay);
|
||||
int flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE;
|
||||
|
||||
String label;
|
||||
if (julianDay == mTodayJulianDay + 1) {
|
||||
label = mContext.getString(R.string.agenda_tomorrow,
|
||||
Utils.formatDateRange(mContext, millis, millis, flags).toString());
|
||||
} else {
|
||||
flags |= DateUtils.FORMAT_SHOW_WEEKDAY;
|
||||
label = Utils.formatDateRange(mContext, millis, millis, flags);
|
||||
}
|
||||
return new DayInfo(julianDay, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("\nCalendarAppWidgetModel [eventInfos=");
|
||||
builder.append(mEventInfos);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@ -16,10 +16,6 @@
|
||||
|
||||
package com.android.calendar.widget;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
@ -36,9 +32,14 @@ import android.widget.RemoteViews;
|
||||
|
||||
import com.android.calendar.AllInOneActivity;
|
||||
import com.android.calendar.EventInfoActivity;
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
|
||||
import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
|
||||
|
||||
/**
|
||||
* Simple widget to show next upcoming calendar event.
|
||||
*/
|
||||
@ -49,6 +50,77 @@ public class CalendarAppWidgetProvider extends AppWidgetProvider {
|
||||
// TODO Move these to Calendar.java
|
||||
static final String EXTRA_EVENT_IDS = "com.android.calendar.EXTRA_EVENT_IDS";
|
||||
|
||||
/**
|
||||
* Build {@link ComponentName} describing this specific
|
||||
* {@link AppWidgetProvider}
|
||||
*/
|
||||
static ComponentName getComponentName(Context context) {
|
||||
return new ComponentName(context, CalendarAppWidgetProvider.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link PendingIntent} used to trigger an update of all calendar
|
||||
* widgets. Uses {@link Utils#getWidgetScheduledUpdateAction(Context)} to
|
||||
* directly target all widgets instead of using
|
||||
* {@link AppWidgetManager#EXTRA_APPWIDGET_IDS}.
|
||||
*
|
||||
* @param context Context to use when building broadcast.
|
||||
*/
|
||||
static PendingIntent getUpdateIntent(Context context) {
|
||||
Intent intent = new Intent(Utils.getWidgetScheduledUpdateAction(context));
|
||||
intent.setDataAndType(CalendarContract.CONTENT_URI, Utils.APPWIDGET_DATA_TYPE);
|
||||
return PendingIntent.getBroadcast(context, 0 /* no requestCode */, intent,
|
||||
0 /* no flags */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link PendingIntent} to launch the Calendar app. This should be used
|
||||
* in combination with {@link RemoteViews#setPendingIntentTemplate(int, PendingIntent)}.
|
||||
*/
|
||||
static PendingIntent getLaunchPendingIntentTemplate(Context context) {
|
||||
Intent launchIntent = new Intent();
|
||||
launchIntent.setAction(Intent.ACTION_VIEW);
|
||||
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
|
||||
Intent.FLAG_ACTIVITY_TASK_ON_HOME);
|
||||
launchIntent.setClass(context, AllInOneActivity.class);
|
||||
return PendingIntent.getActivity(context, 0 /* no requestCode */, launchIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an {@link Intent} available as FillInIntent to launch the Calendar app.
|
||||
* This should be used in combination with
|
||||
* {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
|
||||
* If the go to time is 0, then calendar will be launched without a starting time.
|
||||
*
|
||||
* @param goToTime time that calendar should take the user to, or 0 to
|
||||
* indicate no specific start time.
|
||||
*/
|
||||
static Intent getLaunchFillInIntent(Context context, long id, long start, long end,
|
||||
boolean allDay) {
|
||||
final Intent fillInIntent = new Intent();
|
||||
String dataString = "content://com.android.calendar/events";
|
||||
if (id != 0) {
|
||||
fillInIntent.putExtra(Utils.INTENT_KEY_DETAIL_VIEW, true);
|
||||
fillInIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
|
||||
Intent.FLAG_ACTIVITY_TASK_ON_HOME);
|
||||
|
||||
dataString += "/" + id;
|
||||
// If we have an event id - start the event info activity
|
||||
fillInIntent.setClass(context, EventInfoActivity.class);
|
||||
} else {
|
||||
// If we do not have an event id - start AllInOne
|
||||
fillInIntent.setClass(context, AllInOneActivity.class);
|
||||
}
|
||||
Uri data = Uri.parse(dataString);
|
||||
fillInIntent.setData(data);
|
||||
fillInIntent.putExtra(EXTRA_EVENT_BEGIN_TIME, start);
|
||||
fillInIntent.putExtra(EXTRA_EVENT_END_TIME, end);
|
||||
fillInIntent.putExtra(EXTRA_EVENT_ALL_DAY, allDay);
|
||||
|
||||
return fillInIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -95,15 +167,6 @@ public class CalendarAppWidgetProvider extends AppWidgetProvider {
|
||||
performUpdate(context, appWidgetManager, appWidgetIds, null /* no eventIds */);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build {@link ComponentName} describing this specific
|
||||
* {@link AppWidgetProvider}
|
||||
*/
|
||||
static ComponentName getComponentName(Context context) {
|
||||
return new ComponentName(context, CalendarAppWidgetProvider.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process and push out an update for the given appWidgetIds. This call
|
||||
* actually fires an intent to start {@link CalendarAppWidgetService} as a
|
||||
@ -165,69 +228,6 @@ public class CalendarAppWidgetProvider extends AppWidgetProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link PendingIntent} used to trigger an update of all calendar
|
||||
* widgets. Uses {@link Utils#getWidgetScheduledUpdateAction(Context)} to
|
||||
* directly target all widgets instead of using
|
||||
* {@link AppWidgetManager#EXTRA_APPWIDGET_IDS}.
|
||||
*
|
||||
* @param context Context to use when building broadcast.
|
||||
*/
|
||||
static PendingIntent getUpdateIntent(Context context) {
|
||||
Intent intent = new Intent(Utils.getWidgetScheduledUpdateAction(context));
|
||||
intent.setDataAndType(CalendarContract.CONTENT_URI, Utils.APPWIDGET_DATA_TYPE);
|
||||
return PendingIntent.getBroadcast(context, 0 /* no requestCode */, intent,
|
||||
0 /* no flags */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link PendingIntent} to launch the Calendar app. This should be used
|
||||
* in combination with {@link RemoteViews#setPendingIntentTemplate(int, PendingIntent)}.
|
||||
*/
|
||||
static PendingIntent getLaunchPendingIntentTemplate(Context context) {
|
||||
Intent launchIntent = new Intent();
|
||||
launchIntent.setAction(Intent.ACTION_VIEW);
|
||||
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
|
||||
Intent.FLAG_ACTIVITY_TASK_ON_HOME);
|
||||
launchIntent.setClass(context, AllInOneActivity.class);
|
||||
return PendingIntent.getActivity(context, 0 /* no requestCode */, launchIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an {@link Intent} available as FillInIntent to launch the Calendar app.
|
||||
* This should be used in combination with
|
||||
* {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
|
||||
* If the go to time is 0, then calendar will be launched without a starting time.
|
||||
*
|
||||
* @param goToTime time that calendar should take the user to, or 0 to
|
||||
* indicate no specific start time.
|
||||
*/
|
||||
static Intent getLaunchFillInIntent(Context context, long id, long start, long end,
|
||||
boolean allDay) {
|
||||
final Intent fillInIntent = new Intent();
|
||||
String dataString = "content://com.android.calendar/events";
|
||||
if (id != 0) {
|
||||
fillInIntent.putExtra(Utils.INTENT_KEY_DETAIL_VIEW, true);
|
||||
fillInIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
|
||||
Intent.FLAG_ACTIVITY_TASK_ON_HOME);
|
||||
|
||||
dataString += "/" + id;
|
||||
// If we have an event id - start the event info activity
|
||||
fillInIntent.setClass(context, EventInfoActivity.class);
|
||||
} else {
|
||||
// If we do not have an event id - start AllInOne
|
||||
fillInIntent.setClass(context, AllInOneActivity.class);
|
||||
}
|
||||
Uri data = Uri.parse(dataString);
|
||||
fillInIntent.setData(data);
|
||||
fillInIntent.putExtra(EXTRA_EVENT_BEGIN_TIME, start);
|
||||
fillInIntent.putExtra(EXTRA_EVENT_END_TIME, end);
|
||||
fillInIntent.putExtra(EXTRA_EVENT_ALL_DAY, allDay);
|
||||
|
||||
return fillInIntent;
|
||||
}
|
||||
|
||||
// private static PendingIntent getNewEventPendingIntent(Context context) {
|
||||
// Intent newEventIntent = new Intent(Intent.ACTION_EDIT);
|
||||
// newEventIntent.setClass(context, EditEventActivity.class);
|
||||
|
@ -39,7 +39,6 @@ import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.RemoteViewsService;
|
||||
|
||||
import org.sufficientlysecure.standalonecalendar.R;
|
||||
import com.android.calendar.Utils;
|
||||
import com.android.calendar.widget.CalendarAppWidgetModel.DayInfo;
|
||||
import com.android.calendar.widget.CalendarAppWidgetModel.EventInfo;
|
||||
@ -49,23 +48,14 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import ws.xsoh.etar.R;
|
||||
|
||||
|
||||
public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
private static final String TAG = "CalendarWidget";
|
||||
|
||||
static final int EVENT_MIN_COUNT = 20;
|
||||
static final int EVENT_MAX_COUNT = 100;
|
||||
// Minimum delay between queries on the database for widget updates in ms
|
||||
static final int WIDGET_UPDATE_THROTTLE = 500;
|
||||
|
||||
private static final String EVENT_SORT_ORDER = Instances.START_DAY + " ASC, "
|
||||
+ Instances.START_MINUTE + " ASC, " + Instances.END_DAY + " ASC, "
|
||||
+ Instances.END_MINUTE + " ASC LIMIT " + EVENT_MAX_COUNT;
|
||||
|
||||
private static final String EVENT_SELECTION = Calendars.VISIBLE + "=1";
|
||||
private static final String EVENT_SELECTION_HIDE_DECLINED = Calendars.VISIBLE + "=1 AND "
|
||||
+ Instances.SELF_ATTENDEE_STATUS + "!=" + Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
|
||||
static final String[] EVENT_PROJECTION = new String[] {
|
||||
Instances.ALL_DAY,
|
||||
Instances.BEGIN,
|
||||
@ -78,7 +68,6 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
Instances.DISPLAY_COLOR, // If SDK < 16, set to Instances.CALENDAR_COLOR.
|
||||
Instances.SELF_ATTENDEE_STATUS,
|
||||
};
|
||||
|
||||
static final int INDEX_ALL_DAY = 0;
|
||||
static final int INDEX_BEGIN = 1;
|
||||
static final int INDEX_END = 2;
|
||||
@ -89,21 +78,49 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
static final int INDEX_END_DAY = 7;
|
||||
static final int INDEX_COLOR = 8;
|
||||
static final int INDEX_SELF_ATTENDEE_STATUS = 9;
|
||||
static final int MAX_DAYS = 7;
|
||||
private static final String TAG = "CalendarWidget";
|
||||
private static final String EVENT_SORT_ORDER = Instances.START_DAY + " ASC, "
|
||||
+ Instances.START_MINUTE + " ASC, " + Instances.END_DAY + " ASC, "
|
||||
+ Instances.END_MINUTE + " ASC LIMIT " + EVENT_MAX_COUNT;
|
||||
private static final String EVENT_SELECTION = Calendars.VISIBLE + "=1";
|
||||
private static final String EVENT_SELECTION_HIDE_DECLINED = Calendars.VISIBLE + "=1 AND "
|
||||
+ Instances.SELF_ATTENDEE_STATUS + "!=" + Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
private static final long SEARCH_DURATION = MAX_DAYS * DateUtils.DAY_IN_MILLIS;
|
||||
/**
|
||||
* Update interval used when no next-update calculated, or bad trigger time in past.
|
||||
* Unit: milliseconds.
|
||||
*/
|
||||
private static final long UPDATE_TIME_NO_EVENTS = DateUtils.HOUR_IN_MILLIS * 6;
|
||||
|
||||
static {
|
||||
if (!Utils.isJellybeanOrLater()) {
|
||||
EVENT_PROJECTION[INDEX_COLOR] = Instances.CALENDAR_COLOR;
|
||||
}
|
||||
}
|
||||
static final int MAX_DAYS = 7;
|
||||
|
||||
private static final long SEARCH_DURATION = MAX_DAYS * DateUtils.DAY_IN_MILLIS;
|
||||
|
||||
/**
|
||||
* Update interval used when no next-update calculated, or bad trigger time in past.
|
||||
* Unit: milliseconds.
|
||||
* Format given time for debugging output.
|
||||
*
|
||||
* @param unixTime Target time to report.
|
||||
* @param now Current system time from {@link System#currentTimeMillis()}
|
||||
* for calculating time difference.
|
||||
*/
|
||||
private static final long UPDATE_TIME_NO_EVENTS = DateUtils.HOUR_IN_MILLIS * 6;
|
||||
static String formatDebugTime(long unixTime, long now) {
|
||||
Time time = new Time();
|
||||
time.set(unixTime);
|
||||
|
||||
long delta = unixTime - now;
|
||||
if (delta > DateUtils.MINUTE_IN_MILLIS) {
|
||||
delta /= DateUtils.MINUTE_IN_MILLIS;
|
||||
return String.format("[%d] %s (%+d mins)", unixTime,
|
||||
time.format("%H:%M:%S"), delta);
|
||||
} else {
|
||||
delta /= DateUtils.SECOND_IN_MILLIS;
|
||||
return String.format("[%d] %s (%+d secs)", unixTime,
|
||||
time.format("%H:%M:%S"), delta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteViewsFactory onGetViewFactory(Intent intent) {
|
||||
@ -113,28 +130,21 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
public static class CalendarFactory extends BroadcastReceiver implements
|
||||
RemoteViewsService.RemoteViewsFactory, Loader.OnLoadCompleteListener<Cursor> {
|
||||
private static final boolean LOGD = false;
|
||||
|
||||
private static final AtomicInteger currentVersion = new AtomicInteger(0);
|
||||
// Suppress unnecessary logging about update time. Need to be static as this object is
|
||||
// re-instanciated frequently.
|
||||
// TODO: It seems loadData() is called via onCreate() four times, which should mean
|
||||
// unnecessary CalendarFactory object is created and dropped. It is not efficient.
|
||||
private static long sLastUpdateTime = UPDATE_TIME_NO_EVENTS;
|
||||
|
||||
private Context mContext;
|
||||
private Resources mResources;
|
||||
private static CalendarAppWidgetModel mModel;
|
||||
private static Object mLock = new Object();
|
||||
private static volatile int mSerialNum = 0;
|
||||
private final Handler mHandler = new Handler();
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
private Context mContext;
|
||||
private Resources mResources;
|
||||
private int mLastSerialNum = -1;
|
||||
private CursorLoader mLoader;
|
||||
private final Handler mHandler = new Handler();
|
||||
private static final AtomicInteger currentVersion = new AtomicInteger(0);
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
private int mAppWidgetId;
|
||||
private int mDeclinedColor;
|
||||
private int mStandardColor;
|
||||
private int mAllDayColor;
|
||||
|
||||
private final Runnable mTimezoneChanged = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -143,6 +153,61 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
}
|
||||
}
|
||||
};
|
||||
private int mAppWidgetId;
|
||||
private int mDeclinedColor;
|
||||
private int mStandardColor;
|
||||
private int mAllDayColor;
|
||||
|
||||
protected CalendarFactory(Context context, Intent intent) {
|
||||
mContext = context;
|
||||
mResources = context.getResources();
|
||||
mAppWidgetId = intent.getIntExtra(
|
||||
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||
|
||||
mDeclinedColor = mResources.getColor(R.color.appwidget_item_declined_color);
|
||||
mStandardColor = mResources.getColor(R.color.appwidget_item_standard_color);
|
||||
mAllDayColor = mResources.getColor(R.color.appwidget_item_allday_color);
|
||||
}
|
||||
|
||||
public CalendarFactory() {
|
||||
// This is being created as part of onReceive
|
||||
|
||||
}
|
||||
|
||||
/* @VisibleForTesting */
|
||||
protected static CalendarAppWidgetModel buildAppWidgetModel(
|
||||
Context context, Cursor cursor, String timeZone) {
|
||||
CalendarAppWidgetModel model = new CalendarAppWidgetModel(context, timeZone);
|
||||
model.buildFromCursor(cursor, timeZone);
|
||||
return model;
|
||||
}
|
||||
|
||||
private static long getNextMidnightTimeMillis(String timezone) {
|
||||
Time time = new Time();
|
||||
time.setToNow();
|
||||
time.monthDay++;
|
||||
time.hour = 0;
|
||||
time.minute = 0;
|
||||
time.second = 0;
|
||||
long midnightDeviceTz = time.normalize(true);
|
||||
|
||||
time.timezone = timezone;
|
||||
time.setToNow();
|
||||
time.monthDay++;
|
||||
time.hour = 0;
|
||||
time.minute = 0;
|
||||
time.second = 0;
|
||||
long midnightHomeTz = time.normalize(true);
|
||||
|
||||
return Math.min(midnightDeviceTz, midnightHomeTz);
|
||||
}
|
||||
|
||||
static void updateTextView(RemoteViews views, int id, int visibility, String string) {
|
||||
views.setViewVisibility(id, visibility);
|
||||
if (visibility == View.VISIBLE) {
|
||||
views.setTextViewText(id, string);
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable createUpdateLoaderRunnable(final String selection,
|
||||
final PendingResult result, final int version) {
|
||||
@ -164,22 +229,6 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
};
|
||||
}
|
||||
|
||||
protected CalendarFactory(Context context, Intent intent) {
|
||||
mContext = context;
|
||||
mResources = context.getResources();
|
||||
mAppWidgetId = intent.getIntExtra(
|
||||
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||
|
||||
mDeclinedColor = mResources.getColor(R.color.appwidget_item_declined_color);
|
||||
mStandardColor = mResources.getColor(R.color.appwidget_item_standard_color);
|
||||
mAllDayColor = mResources.getColor(R.color.appwidget_item_allday_color);
|
||||
}
|
||||
|
||||
public CalendarFactory() {
|
||||
// This is being created as part of onReceive
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
String selection = queryForSelection();
|
||||
@ -409,14 +458,6 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
return uri;
|
||||
}
|
||||
|
||||
/* @VisibleForTesting */
|
||||
protected static CalendarAppWidgetModel buildAppWidgetModel(
|
||||
Context context, Cursor cursor, String timeZone) {
|
||||
CalendarAppWidgetModel model = new CalendarAppWidgetModel(context, timeZone);
|
||||
model.buildFromCursor(cursor, timeZone);
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates and returns the next time we should push widget updates.
|
||||
*/
|
||||
@ -439,33 +480,6 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
return minUpdateTime;
|
||||
}
|
||||
|
||||
private static long getNextMidnightTimeMillis(String timezone) {
|
||||
Time time = new Time();
|
||||
time.setToNow();
|
||||
time.monthDay++;
|
||||
time.hour = 0;
|
||||
time.minute = 0;
|
||||
time.second = 0;
|
||||
long midnightDeviceTz = time.normalize(true);
|
||||
|
||||
time.timezone = timezone;
|
||||
time.setToNow();
|
||||
time.monthDay++;
|
||||
time.hour = 0;
|
||||
time.minute = 0;
|
||||
time.second = 0;
|
||||
long midnightHomeTz = time.normalize(true);
|
||||
|
||||
return Math.min(midnightDeviceTz, midnightHomeTz);
|
||||
}
|
||||
|
||||
static void updateTextView(RemoteViews views, int id, int visibility, String string) {
|
||||
views.setViewVisibility(id, visibility);
|
||||
if (visibility == View.VISIBLE) {
|
||||
views.setTextViewText(id, string);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
@ -599,27 +613,4 @@ public class CalendarAppWidgetService extends RemoteViewsService {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format given time for debugging output.
|
||||
*
|
||||
* @param unixTime Target time to report.
|
||||
* @param now Current system time from {@link System#currentTimeMillis()}
|
||||
* for calculating time difference.
|
||||
*/
|
||||
static String formatDebugTime(long unixTime, long now) {
|
||||
Time time = new Time();
|
||||
time.set(unixTime);
|
||||
|
||||
long delta = unixTime - now;
|
||||
if (delta > DateUtils.MINUTE_IN_MILLIS) {
|
||||
delta /= DateUtils.MINUTE_IN_MILLIS;
|
||||
return String.format("[%d] %s (%+d mins)", unixTime,
|
||||
time.format("%H:%M:%S"), delta);
|
||||
} else {
|
||||
delta /= DateUtils.SECOND_IN_MILLIS;
|
||||
return String.format("[%d] %s (%+d secs)", unixTime,
|
||||
time.format("%H:%M:%S"), delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user