summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamian Patel <damianpatel@google.com>2021-07-08 15:18:49 +0000
committerDamian Patel <damianpatel@google.com>2021-07-08 15:18:49 +0000
commit2cba2a7819d117d7adabf9b77cf1c4d12b920bed (patch)
tree4d947fd510d949992f03d52860545fcfe1336d1f
parent9b3c5ce1f330b40bf072cf78069082ded3813cb3 (diff)
downloadCalendar-2cba2a7819d117d7adabf9b77cf1c4d12b920bed.tar.gz
AOSP/Calendar - Copy of EventInfoFragment.java
The Java code in Event EventInfoFragment.java has been copied into a corresponding .kt file. Test: manual - opening both files shows that they are identical. Change-Id: I49c7240ba4ea471d7cc0fae53f402dfaf29b73c8
-rw-r--r--src/com/android/calendar/EventInfoFragment.kt877
1 files changed, 877 insertions, 0 deletions
diff --git a/src/com/android/calendar/EventInfoFragment.kt b/src/com/android/calendar/EventInfoFragment.kt
new file mode 100644
index 00000000..0aa83d02
--- /dev/null
+++ b/src/com/android/calendar/EventInfoFragment.kt
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.calendar;
+
+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;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.Service;
+import android.content.ActivityNotFoundException;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.CalendarContract;
+import android.provider.CalendarContract.Attendees;
+import android.provider.CalendarContract.Calendars;
+import android.provider.CalendarContract.Events;
+import android.provider.CalendarContract.Reminders;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.QuickContact;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.format.Time;
+import android.text.method.LinkMovementMethod;
+import android.text.method.MovementMethod;
+import android.text.style.ForegroundColorSpan;
+import android.text.util.Rfc822Token;
+import android.util.Log;
+import android.util.SparseIntArray;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.RadioGroup.OnCheckedChangeListener;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.calendar.CalendarController.EventInfo;
+import com.android.calendar.CalendarController.EventType;
+import com.android.calendar.alerts.QuickResponseActivity;
+import com.android.calendarcommon2.DateException;
+import com.android.calendarcommon2.Duration;
+import com.android.calendarcommon2.EventRecurrence;
+import com.android.colorpicker.HsvColorComparator;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class EventInfoFragment extends DialogFragment implements OnCheckedChangeListener,
+ CalendarController.EventHandler, OnClickListener {
+
+ public static final boolean DEBUG = false;
+
+ public static final String TAG = "EventInfoFragment";
+
+ 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";
+ protected static final String BUNDLE_KEY_IS_DIALOG = "key_fragment_is_dialog";
+ protected static final String BUNDLE_KEY_DELETE_DIALOG_VISIBLE = "key_delete_dialog_visible";
+ protected static final String BUNDLE_KEY_WINDOW_STYLE = "key_window_style";
+ protected static final String BUNDLE_KEY_CALENDAR_COLOR = "key_calendar_color";
+ protected static final String BUNDLE_KEY_CALENDAR_COLOR_INIT = "key_calendar_color_init";
+ protected static final String BUNDLE_KEY_CURRENT_COLOR = "key_current_color";
+ protected static final String BUNDLE_KEY_CURRENT_COLOR_KEY = "key_current_color_key";
+ protected static final String BUNDLE_KEY_CURRENT_COLOR_INIT = "key_current_color_init";
+ protected static final String BUNDLE_KEY_ORIGINAL_COLOR = "key_original_color";
+ protected static final String BUNDLE_KEY_ORIGINAL_COLOR_INIT = "key_original_color_init";
+ protected static final String BUNDLE_KEY_ATTENDEE_RESPONSE = "key_attendee_response";
+ protected static final String BUNDLE_KEY_USER_SET_ATTENDEE_RESPONSE =
+ "key_user_set_attendee_response";
+ protected static final String BUNDLE_KEY_TENTATIVE_USER_RESPONSE =
+ "key_tentative_user_response";
+ 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;
+
+ // Query tokens for QueryHandler
+ private static final int TOKEN_QUERY_EVENT = 1 << 0;
+ private static final int TOKEN_QUERY_CALENDARS = 1 << 1;
+ private static final int TOKEN_QUERY_ATTENDEES = 1 << 2;
+ private static final int TOKEN_QUERY_DUPLICATE_CALENDARS = 1 << 3;
+ 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
+ Events.RRULE, // 2 do not remove; used in DeleteEventHelper
+ Events.ALL_DAY, // 3 do not remove; used in DeleteEventHelper
+ Events.CALENDAR_ID, // 4 do not remove; used in DeleteEventHelper
+ Events.DTSTART, // 5 do not remove; used in DeleteEventHelper
+ Events._SYNC_ID, // 6 do not remove; used in DeleteEventHelper
+ Events.EVENT_TIMEZONE, // 7 do not remove; used in DeleteEventHelper
+ Events.DESCRIPTION, // 8
+ Events.EVENT_LOCATION, // 9
+ Calendars.CALENDAR_ACCESS_LEVEL, // 10
+ Events.CALENDAR_COLOR, // 11
+ Events.EVENT_COLOR, // 12
+ Events.HAS_ATTENDEE_DATA, // 13
+ Events.ORGANIZER, // 14
+ Events.HAS_ALARM, // 15
+ Calendars.MAX_REMINDERS, // 16
+ Calendars.ALLOWED_REMINDERS, // 17
+ Events.CUSTOM_APP_PACKAGE, // 18
+ Events.CUSTOM_APP_URI, // 19
+ Events.DTEND, // 20
+ Events.DURATION, // 21
+ Events.ORIGINAL_SYNC_ID // 22 do not remove; used in DeleteEventHelper
+ };
+ private static final int EVENT_INDEX_ID = 0;
+ private static final int EVENT_INDEX_TITLE = 1;
+ private static final int EVENT_INDEX_RRULE = 2;
+ private static final int EVENT_INDEX_ALL_DAY = 3;
+ private static final int EVENT_INDEX_CALENDAR_ID = 4;
+ private static final int EVENT_INDEX_DTSTART = 5;
+ private static final int EVENT_INDEX_SYNC_ID = 6;
+ private static final int EVENT_INDEX_EVENT_TIMEZONE = 7;
+ private static final int EVENT_INDEX_DESCRIPTION = 8;
+ private static final int EVENT_INDEX_EVENT_LOCATION = 9;
+ private static final int EVENT_INDEX_ACCESS_LEVEL = 10;
+ private static final int EVENT_INDEX_CALENDAR_COLOR = 11;
+ private static final int EVENT_INDEX_EVENT_COLOR = 12;
+ private static final int EVENT_INDEX_HAS_ATTENDEE_DATA = 13;
+ private static final int EVENT_INDEX_ORGANIZER = 14;
+ private static final int EVENT_INDEX_HAS_ALARM = 15;
+ private static final int EVENT_INDEX_MAX_REMINDERS = 16;
+ private static final int EVENT_INDEX_ALLOWED_REMINDERS = 17;
+ private static final int EVENT_INDEX_CUSTOM_APP_PACKAGE = 18;
+ 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;
+
+ static {
+ if (!Utils.isJellybeanOrLater()) {
+ EVENT_PROJECTION[EVENT_INDEX_CUSTOM_APP_PACKAGE] = Events._ID; // nonessential value
+ EVENT_PROJECTION[EVENT_INDEX_CUSTOM_APP_URI] = Events._ID; // nonessential value
+ }
+ }
+
+ 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 + "=?";
+
+ public static final int COLORS_INDEX_COLOR = 1;
+ public static final int COLORS_INDEX_COLOR_KEY = 2;
+
+ private View mView;
+
+ private Uri mUri;
+ private long mEventId;
+ private Cursor mEventCursor;
+ private Cursor mCalendarsCursor;
+
+ 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 mOwnerCanRespond;
+ private String mSyncAccountName;
+ private String mCalendarOwnerAccount;
+ private boolean mIsBusyFreeCalendar;
+
+ private int mOriginalAttendeeResponse;
+ private int mAttendeeResponseFromIntent = Attendees.ATTENDEE_STATUS_NONE;
+ private int mUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
+ private int mWhichEvents = -1;
+ // Used as the temporary response until the dialog is confirmed. It is also
+ // able to be used as a state marker for configuration changes.
+ private int mTentativeUserSetResponse = Attendees.ATTENDEE_STATUS_NONE;
+ private boolean mHasAlarm;
+ // 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;
+ private Menu mMenu = null;
+ private View mHeadlines;
+ private ScrollView mScrollView;
+ private View mLoadingMsgView;
+ private View mErrorMsgView;
+ private ObjectAnimator mAnimateAlpha;
+ private long mLoadingMsgStartTime;
+
+ private SparseIntArray mDisplayColorKeyMap = new SparseIntArray();
+ 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<String> mToEmails = new ArrayList<String>();
+ ArrayList<String> mCcEmails = new ArrayList<String>();
+
+
+ private final Runnable mTZUpdater = new Runnable() {
+ @Override
+ public void run() {
+ updateEvent(mView);
+ }
+ };
+
+ private final Runnable mLoadingMsgAlphaUpdater = new Runnable() {
+ @Override
+ public void run() {
+ // Since this is run after a delay, make sure to only show the message
+ // if the event's data is not shown yet.
+ if (!mAnimateAlpha.isRunning() && mScrollView.getAlpha() == 0) {
+ mLoadingMsgStartTime = System.currentTimeMillis();
+ mLoadingMsgView.setAlpha(1);
+ }
+ }
+ };
+
+ 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 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 void sendAccessibilityEventIfQueryDone(int token) {
+ mCurrentQuery |= token;
+ if (mCurrentQuery == TOKEN_QUERY_ALL) {
+ sendAccessibilityEvent();
+ }
+ }
+
+ public EventInfoFragment(Context context, Uri uri, long startMillis, long endMillis,
+ int attendeeResponse, boolean isDialog, int windowStyle) {
+
+ Resources r = context.getResources();
+ if (mScale == 0) {
+ mScale = context.getResources().getDisplayMetrics().density;
+ if (mScale != 1) {
+ mCustomAppIconSize *= mScale;
+ if (isDialog) {
+ DIALOG_TOP_MARGIN *= mScale;
+ }
+ }
+ }
+ if (isDialog) {
+ setDialogSize(r);
+ }
+ mIsDialog = isDialog;
+
+ setStyle(DialogFragment.STYLE_NO_TITLE, 0);
+ mUri = uri;
+ mStartMillis = startMillis;
+ mEndMillis = endMillis;
+ mAttendeeResponseFromIntent = attendeeResponse;
+ mWindowStyle = windowStyle;
+ }
+
+ // This is currently required by the fragment manager.
+ public EventInfoFragment() {
+ }
+
+ public EventInfoFragment(Context context, long eventId, long startMillis, long endMillis,
+ int attendeeResponse, boolean isDialog, int windowStyle) {
+ this(context, ContentUris.withAppendedId(Events.CONTENT_URI, eventId), startMillis,
+ endMillis, attendeeResponse, isDialog, windowStyle);
+ mEventId = eventId;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (mIsDialog) {
+ applyDialogParams();
+ }
+
+ final Activity activity = getActivity();
+ mContext = activity;
+ }
+
+ private void applyDialogParams() {
+ Dialog dialog = getDialog();
+ dialog.setCanceledOnTouchOutside(true);
+
+ Window window = dialog.getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+
+ WindowManager.LayoutParams a = window.getAttributes();
+ a.dimAmount = .4f;
+
+ a.width = mDialogWidth;
+ a.height = mDialogHeight;
+
+
+ // On tablets , do smart positioning of dialog
+ // On phones , use the whole screen
+
+ if (mX != -1 || mY != -1) {
+ a.x = mX - mDialogWidth / 2;
+ a.y = mY - mDialogHeight / 2;
+ if (a.y < mMinTop) {
+ a.y = mMinTop + DIALOG_TOP_MARGIN;
+ }
+ a.gravity = Gravity.LEFT | Gravity.TOP;
+ }
+ window.setAttributes(a);
+ }
+
+ public void setDialogParams(int x, int y, int minTop) {
+ mX = x;
+ mY = y;
+ mMinTop = minTop;
+ }
+
+ // Implements OnCheckedChangeListener
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ }
+
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mController.deregisterEventHandler(R.layout.event_info);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mActivity = activity;
+ // Ensure that mIsTabletConfig is set before creating the menu.
+ mIsTabletConfig = Utils.getConfigBool(mActivity, R.bool.tablet_config);
+ mController = CalendarController.getInstance(mActivity);
+ mController.registerEventHandler(R.layout.event_info, this);
+
+ if (!mIsDialog) {
+ setHasOptionsMenu(true);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ if (mWindowStyle == DIALOG_WINDOW_STYLE) {
+ mView = inflater.inflate(R.layout.event_info_dialog, container, false);
+ } else {
+ mView = inflater.inflate(R.layout.event_info, container, false);
+ }
+ mScrollView = (ScrollView) mView.findViewById(R.id.event_info_scroll_view);
+ mLoadingMsgView = mView.findViewById(R.id.event_info_loading_msg);
+ mErrorMsgView = mView.findViewById(R.id.event_info_error_msg);
+ mTitle = (TextView) mView.findViewById(R.id.title);
+ mWhenDateTime = (TextView) mView.findViewById(R.id.when_datetime);
+ mWhere = (TextView) mView.findViewById(R.id.where);
+ mHeadlines = mView.findViewById(R.id.event_info_headline);
+
+ mResponseRadioGroup = (RadioGroup) mView.findViewById(R.id.response_value);
+
+ mAnimateAlpha = ObjectAnimator.ofFloat(mScrollView, "Alpha", 0, 1);
+ mAnimateAlpha.setDuration(FADE_IN_TIME);
+ mAnimateAlpha.addListener(new AnimatorListenerAdapter() {
+ int defLayerType;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Use hardware layer for better performance during animation
+ defLayerType = mScrollView.getLayerType();
+ mScrollView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ // Ensure that the loading message is gone before showing the
+ // event info
+ mLoadingMsgView.removeCallbacks(mLoadingMsgAlphaUpdater);
+ mLoadingMsgView.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mScrollView.setLayerType(defLayerType, null);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mScrollView.setLayerType(defLayerType, null);
+ // Do not cross fade after the first time
+ mNoCrossFade = true;
+ }
+ });
+
+ mLoadingMsgView.setAlpha(0);
+ mScrollView.setAlpha(0);
+ mErrorMsgView.setVisibility(View.INVISIBLE);
+ mLoadingMsgView.postDelayed(mLoadingMsgAlphaUpdater, LOADING_MSG_DELAY);
+
+ // Hide Edit/Delete buttons if in full screen mode on a phone
+ if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) {
+ mView.findViewById(R.id.event_info_buttons_container).setVisibility(View.GONE);
+ }
+
+ return mView;
+ }
+
+ private void updateTitle() {
+ Resources res = getActivity().getResources();
+ getActivity().setTitle(res.getString(R.string.event_info_title));
+ }
+
+ /**
+ * Initializes the event cursor, which is expected to point to the first
+ * (and only) result from a query.
+ * @return false if the cursor is empty, true otherwise
+ */
+ private boolean initEventCursor() {
+ if ((mEventCursor == null) || (mEventCursor.getCount() == 0)) {
+ return false;
+ }
+ mEventCursor.moveToFirst();
+ mEventId = mEventCursor.getInt(EVENT_INDEX_ID);
+ String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
+ // mHasAlarm will be true if it was saved in the event already.
+ mHasAlarm = (mEventCursor.getInt(EVENT_INDEX_HAS_ALARM) == 1)? true : false;
+ return true;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ // Show color/edit/delete buttons only in non-dialog configuration
+ if (!mIsDialog && !mIsTabletConfig || mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) {
+ inflater.inflate(R.menu.event_info_title_bar, menu);
+ mMenu = menu;
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+
+ // If we're a dialog we don't want to handle menu buttons
+ if (mIsDialog) {
+ return false;
+ }
+ // Handles option menu selections:
+ // Home button - close event info activity and start the main calendar
+ // one
+ // Edit button - start the event edit activity and close the info
+ // activity
+ // Delete button - start a delete query that calls a runnable that close
+ // the info activity
+
+ final int itemId = item.getItemId();
+ if (itemId == android.R.id.home) {
+ Utils.returnToCalendarHome(mContext);
+ mActivity.finish();
+ return true;
+ } else if (itemId == R.id.info_action_edit) {
+ mActivity.finish();
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mEventCursor != null) {
+ mEventCursor.close();
+ }
+ if (mCalendarsCursor != null) {
+ mCalendarsCursor.close();
+ }
+ super.onDestroy();
+ }
+
+ /**
+ * Creates an exception to a recurring event. The only change we're making is to the
+ * "self attendee status" value. The provider will take care of updating the corresponding
+ * Attendees.attendeeStatus entry.
+ *
+ * @param eventId The recurring event.
+ * @param status The new value for selfAttendeeStatus.
+ */
+ private void createExceptionResponse(long eventId, int status) {
+ ContentValues values = new ContentValues();
+ values.put(Events.ORIGINAL_INSTANCE_TIME, mStartMillis);
+ values.put(Events.SELF_ATTENDEE_STATUS, status);
+ values.put(Events.STATUS, Events.STATUS_CONFIRMED);
+
+ ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
+ Uri exceptionUri = Uri.withAppendedPath(Events.CONTENT_EXCEPTION_URI,
+ String.valueOf(eventId));
+ ops.add(ContentProviderOperation.newInsert(exceptionUri).withValues(values).build());
+ }
+
+ public static int getResponseFromButtonId(int buttonId) {
+ return Attendees.ATTENDEE_STATUS_NONE;
+ }
+
+ public static int findButtonIdForResponse(int response) {
+ return -1;
+ }
+
+ private void displayEventNotFound() {
+ mErrorMsgView.setVisibility(View.VISIBLE);
+ mScrollView.setVisibility(View.GONE);
+ mLoadingMsgView.setVisibility(View.GONE);
+ }
+
+ private void updateEvent(View view) {
+ if (mEventCursor == null || view == null) {
+ return;
+ }
+
+ Context context = view.getContext();
+ if (context == null) {
+ return;
+ }
+
+ String eventName = mEventCursor.getString(EVENT_INDEX_TITLE);
+ if (eventName == null || eventName.length() == 0) {
+ eventName = getActivity().getString(R.string.no_title_label);
+ }
+
+ // 3rd parties might not have specified the start/end time when firing the
+ // Events.CONTENT_URI intent. Update these with values read from the db.
+ if (mStartMillis == 0 && mEndMillis == 0) {
+ mStartMillis = mEventCursor.getLong(EVENT_INDEX_DTSTART);
+ mEndMillis = mEventCursor.getLong(EVENT_INDEX_DTEND);
+ if (mEndMillis == 0) {
+ String duration = mEventCursor.getString(EVENT_INDEX_DURATION);
+ if (!TextUtils.isEmpty(duration)) {
+ try {
+ Duration d = new Duration();
+ d.parse(duration);
+ long endMillis = mStartMillis + d.getMillis();
+ if (endMillis >= mStartMillis) {
+ mEndMillis = endMillis;
+ } else {
+ Log.d(TAG, "Invalid duration string: " + duration);
+ }
+ } catch (DateException e) {
+ Log.d(TAG, "Error parsing duration string " + duration, e);
+ }
+ }
+ if (mEndMillis == 0) {
+ mEndMillis = mStartMillis;
+ }
+ }
+ }
+
+ mAllDay = mEventCursor.getInt(EVENT_INDEX_ALL_DAY) != 0;
+ String location = mEventCursor.getString(EVENT_INDEX_EVENT_LOCATION);
+ String description = mEventCursor.getString(EVENT_INDEX_DESCRIPTION);
+ String rRule = mEventCursor.getString(EVENT_INDEX_RRULE);
+ String eventTimezone = mEventCursor.getString(EVENT_INDEX_EVENT_TIMEZONE);
+
+ mHeadlines.setBackgroundColor(mCurrentColor);
+
+ // What
+ if (eventName != null) {
+ setTextCommon(view, R.id.title, eventName);
+ }
+
+ // When
+ // Set the date and repeats (if any)
+ String localTimezone = Utils.getTimeZone(mActivity, mTZUpdater);
+
+ Resources resources = context.getResources();
+ String displayedDatetime = Utils.getDisplayedDatetime(mStartMillis, mEndMillis,
+ System.currentTimeMillis(), localTimezone, mAllDay, context);
+
+ String displayedTimezone = null;
+ if (!mAllDay) {
+ displayedTimezone = Utils.getDisplayedTimezone(mStartMillis, localTimezone,
+ eventTimezone);
+ }
+ // Display the datetime. Make the timezone (if any) transparent.
+ if (displayedTimezone == null) {
+ setTextCommon(view, R.id.when_datetime, displayedDatetime);
+ } else {
+ int timezoneIndex = displayedDatetime.length();
+ displayedDatetime += " " + displayedTimezone;
+ SpannableStringBuilder sb = new SpannableStringBuilder(displayedDatetime);
+ ForegroundColorSpan transparentColorSpan = new ForegroundColorSpan(
+ resources.getColor(R.color.event_info_headline_transparent_color));
+ sb.setSpan(transparentColorSpan, timezoneIndex, displayedDatetime.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ setTextCommon(view, R.id.when_datetime, sb);
+ }
+
+ view.findViewById(R.id.when_repeat).setVisibility(View.GONE);
+
+ // Organizer view is setup in the updateCalendar method
+
+
+ // Where
+ if (location == null || location.trim().length() == 0) {
+ setVisibilityCommon(view, R.id.where, View.GONE);
+ } else {
+ final TextView textView = mWhere;
+ if (textView != null) {
+ textView.setText(location.trim());
+ }
+ }
+
+ // Launch Custom App
+ if (Utils.isJellybeanOrLater()) {
+ updateCustomAppButton();
+ }
+ }
+
+ private void updateCustomAppButton() {
+ setVisibilityCommon(mView, R.id.launch_custom_app_container, View.GONE);
+ return;
+ }
+
+ private void sendAccessibilityEvent() {
+ AccessibilityManager am =
+ (AccessibilityManager) getActivity().getSystemService(Service.ACCESSIBILITY_SERVICE);
+ if (!am.isEnabled()) {
+ return;
+ }
+
+ AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ event.setClassName(EventInfoFragment.class.getName());
+ event.setPackageName(getActivity().getPackageName());
+ List<CharSequence> text = event.getText();
+
+ if (mResponseRadioGroup.getVisibility() == View.VISIBLE) {
+ int id = mResponseRadioGroup.getCheckedRadioButtonId();
+ if (id != View.NO_ID) {
+ text.add(((TextView) getView().findViewById(R.id.response_label)).getText());
+ text.add((((RadioButton) (mResponseRadioGroup.findViewById(id)))
+ .getText() + PERIOD_SPACE));
+ }
+ }
+
+ am.sendAccessibilityEvent(event);
+ }
+
+ private void updateCalendar(View view) {
+
+ mCalendarOwnerAccount = "";
+ if (mCalendarsCursor != null && mEventCursor != null) {
+ mCalendarsCursor.moveToFirst();
+ String tempAccount = mCalendarsCursor.getString(CALENDARS_INDEX_OWNER_ACCOUNT);
+ mCalendarOwnerAccount = (tempAccount == null) ? "" : tempAccount;
+ mOwnerCanRespond = mCalendarsCursor.getInt(CALENDARS_INDEX_OWNER_CAN_RESPOND) != 0;
+ mSyncAccountName = mCalendarsCursor.getString(CALENDARS_INDEX_ACCOUNT_NAME);
+
+ setVisibilityCommon(view, R.id.organizer_container, View.GONE);
+ mIsBusyFreeCalendar =
+ mEventCursor.getInt(EVENT_INDEX_ACCESS_LEVEL) == Calendars.CAL_ACCESS_FREEBUSY;
+
+ if (!mIsBusyFreeCalendar) {
+
+ View b = mView.findViewById(R.id.edit);
+ b.setEnabled(true);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // For dialogs, just close the fragment
+ // For full screen, close activity on phone, leave it for tablet
+ if (mIsDialog) {
+ EventInfoFragment.this.dismiss();
+ }
+ else if (!mIsTabletConfig){
+ getActivity().finish();
+ }
+ }
+ });
+ }
+ View button;
+ if ((!mIsDialog && !mIsTabletConfig ||
+ mWindowStyle == EventInfoFragment.FULL_WINDOW_STYLE) && mMenu != null) {
+ mActivity.invalidateOptionsMenu();
+ }
+ } else {
+ setVisibilityCommon(view, R.id.calendar, View.GONE);
+ sendAccessibilityEventIfQueryDone(TOKEN_QUERY_DUPLICATE_CALENDARS);
+ }
+ }
+
+ private void setTextCommon(View view, int id, CharSequence text) {
+ TextView textView = (TextView) view.findViewById(id);
+ if (textView == null)
+ return;
+ textView.setText(text);
+ }
+
+ private void setVisibilityCommon(View view, int id, int visibility) {
+ View v = view.findViewById(id);
+ if (v != null) {
+ v.setVisibility(visibility);
+ }
+ return;
+ }
+
+ @Override
+ public void onPause() {
+ mIsPaused = true;
+ super.onPause();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mIsDialog) {
+ setDialogSize(getActivity().getResources());
+ applyDialogParams();
+ }
+ mIsPaused = false;
+ if (mTentativeUserSetResponse != Attendees.ATTENDEE_STATUS_NONE) {
+ int buttonId = findButtonIdForResponse(mTentativeUserSetResponse);
+ mResponseRadioGroup.check(buttonId);
+ }
+ }
+
+ @Override
+ public void eventsChanged() {
+ }
+
+ @Override
+ public long getSupportedEventTypes() {
+ return EventType.EVENTS_CHANGED;
+ }
+
+ @Override
+ public void handleEvent(EventInfo event) {
+ reloadEvents();
+ }
+
+ public void reloadEvents() {
+ }
+
+ @Override
+ public void onClick(View view) {
+ }
+
+ public long getEventId() {
+ return mEventId;
+ }
+
+ 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);
+ }
+}