From 3a7bb238b2c9a53e7880857ac6329c7c9385199b Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Tue, 29 Jan 2019 16:52:48 +0100 Subject: [PATCH 1/2] Add a calendar widget to the widget list. (Rebase) --- .../e/blisslauncher/core/Preferences.java | 88 ++++++++- .../e/blisslauncher/core/Preferences.java | 68 +++++++ app/src/main/AndroidManifest.xml | 2 + .../e/blisslauncher/core/utils/Constants.java | 8 + .../features/calendar/CalendarEvent.java | 97 +++++++++ .../calendar/CalendarUpdateService.java | 187 ++++++++++++++++++ .../features/calendar/EventlistBuilder.java | 142 +++++++++++++ .../features/launcher/LauncherActivity.java | 109 +++++++--- app/src/main/res/layout/item_calendar_day.xml | 47 +++++ .../main/res/layout/item_calendar_event.xml | 50 +++++ .../main/res/layout/layout_calendar_info.xml | 50 +++++ app/src/main/res/layout/widgets_page.xml | 3 +- app/src/main/res/values/strings.xml | 2 + 13 files changed, 819 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarEvent.java create mode 100644 app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarUpdateService.java create mode 100644 app/src/main/java/foundation/e/blisslauncher/features/calendar/EventlistBuilder.java create mode 100644 app/src/main/res/layout/item_calendar_day.xml create mode 100644 app/src/main/res/layout/item_calendar_event.xml create mode 100644 app/src/main/res/layout/layout_calendar_info.xml diff --git a/app/src/apiNougat/java/foundation/e/blisslauncher/core/Preferences.java b/app/src/apiNougat/java/foundation/e/blisslauncher/core/Preferences.java index 2e51922bef..662bc894f0 100644 --- a/app/src/apiNougat/java/foundation/e/blisslauncher/core/Preferences.java +++ b/app/src/apiNougat/java/foundation/e/blisslauncher/core/Preferences.java @@ -3,16 +3,19 @@ package foundation.e.blisslauncher.core; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; +import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; +import java.util.List; import java.util.Locale; import cyanogenmod.weather.WeatherInfo; import cyanogenmod.weather.WeatherLocation; +import foundation.e.blisslauncher.features.calendar.CalendarEvent; import foundation.e.blisslauncher.core.utils.Constants; public class Preferences { @@ -48,6 +51,13 @@ public class Preferences { private static final String ENABLE_LOCATION = "enable_location"; + private static final String CALENDAR_EVENT_ID = "eventId"; + private static final String CALENDAR_EVENT_TITLE = "title"; + private static final String CALENDAR_EVENT_ALLDAY = "all_day"; + private static final String CALENDAR_EVENT_START_MILLIS = "start_millis"; + private static final String CALENDAR_EVENT_END_MILLIS = "end_millis"; + private static final String CALENDAR_EVENT_LOCATION = "location"; + private static final String CALENDAR_EVENT_COLOR = "color"; /** * User Preference related keys and constants. @@ -113,7 +123,7 @@ public class Preferences { } public static boolean setCustomWeatherLocation(Context context, - WeatherLocation weatherLocation) { + WeatherLocation weatherLocation) { if (weatherLocation == null) { getPrefs(context).edit() .remove(Constants.WEATHER_CUSTOM_LOCATION).apply(); @@ -333,27 +343,27 @@ public class Preferences { getPrefs(context).edit().putLong(key, System.currentTimeMillis()).apply(); } - public static boolean isFirstTime(Context context){ + public static boolean isFirstTime(Context context) { return getPrefs(context).getBoolean(FIRST_TIME, true); } - public static void setFirstTimeDone(Context context){ + public static void setFirstTimeDone(Context context) { getPrefs(context).edit().putBoolean(FIRST_TIME, false).apply(); } - public static boolean shouldOpenUsageAccess(Context context){ + public static boolean shouldOpenUsageAccess(Context context) { return getPrefs(context).getBoolean(ACTION_USAGE, true); } - public static void setNotOpenUsageAccess(Context context){ + public static void setNotOpenUsageAccess(Context context) { getPrefs(context).edit().putBoolean(ACTION_USAGE, false).apply(); } - public static boolean getNotificationAccess(Context context){ + public static boolean getNotificationAccess(Context context) { return getPrefs(context).getBoolean(NOTIFICATION_ACCESS, false); } - public static void setNotificationAccess(Context context){ + public static void setNotificationAccess(Context context) { getPrefs(context).edit().putBoolean(NOTIFICATION_ACCESS, true).apply(); } @@ -369,4 +379,68 @@ public class Preferences { Context context) { return getPrefs(context).getBoolean(ENABLE_LOCATION, false); } + + + public static int calendarFontColor(Context context) { + return Color.parseColor(getPrefs(context).getString(Constants.CALENDAR_FONT_COLOR, + Constants.DEFAULT_LIGHT_COLOR)); + } + + public static void setCachedCalendarEvents(Context context, List events) { + SharedPreferences.Editor editor = getPrefs(context).edit(); + boolean serialized = false; + if (events != null && events.size() > 0) { + JSONArray cacheList = new JSONArray(); + try { + for (CalendarEvent ev : events) { + JSONObject cacheEvent = new JSONObject(); + cacheEvent.put(CALENDAR_EVENT_ID, ev.getEventId()) + .put(CALENDAR_EVENT_TITLE, ev.getTitle()) + .put(CALENDAR_EVENT_ALLDAY, ev.isAllDay()) + .put(CALENDAR_EVENT_START_MILLIS, ev.getStartMillis()) + .put(CALENDAR_EVENT_END_MILLIS, ev.getEndMillis()) + .put(CALENDAR_EVENT_LOCATION, ev.getLocation()) + .put(CALENDAR_EVENT_COLOR, ev.getCalendarColor()); + cacheList.put(cacheEvent); + } + serialized = true; + } catch (JSONException ignored) { + // We're here because something went wrong while creating the JSON object. + // The code below will check for success and proceed accordingly + } + if (serialized) + editor.putString(Constants.CALENDAR_DATA, cacheList.toString()); + } else { + editor.remove(Constants.CALENDAR_DATA); + } + editor.apply(); + } + + public static List getCachedCalendarEvents(Context context) { + List retArray = new ArrayList<>(); + final String cachedData = getPrefs(context).getString(Constants.CALENDAR_DATA, null); + if (cachedData == null) return null; + + JSONObject last = null; + try { + JSONArray cachedEvents = new JSONArray(cachedData); + for (int indx = 0; indx < cachedEvents.length(); indx++) { + JSONObject cachedEvent = cachedEvents.getJSONObject(indx); + last = cachedEvent; + retArray.add(new CalendarEvent(context, + cachedEvent.getInt(CALENDAR_EVENT_ID), + cachedEvent.optString(CALENDAR_EVENT_TITLE, ""), + cachedEvent.getBoolean(CALENDAR_EVENT_ALLDAY), + cachedEvent.getLong(CALENDAR_EVENT_START_MILLIS), + cachedEvent.getLong(CALENDAR_EVENT_END_MILLIS), + cachedEvent.optString(CALENDAR_EVENT_LOCATION, ""), + cachedEvent.getInt(CALENDAR_EVENT_COLOR))); + } + } catch (JSONException ignored) { + Log.e("Preferences", ignored.toString()); + if(last != null) + Log.d("Preferences", last.toString()); + } + return retArray; + } } diff --git a/app/src/apiOreo/java/foundation/e/blisslauncher/core/Preferences.java b/app/src/apiOreo/java/foundation/e/blisslauncher/core/Preferences.java index e12e7410a9..745914e619 100644 --- a/app/src/apiOreo/java/foundation/e/blisslauncher/core/Preferences.java +++ b/app/src/apiOreo/java/foundation/e/blisslauncher/core/Preferences.java @@ -3,15 +3,18 @@ package foundation.e.blisslauncher.core; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; +import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; +import java.util.List; import java.util.Locale; import foundation.e.blisslauncher.core.utils.Constants; +import foundation.e.blisslauncher.features.calendar.CalendarEvent; import lineageos.weather.WeatherInfo; import lineageos.weather.WeatherLocation; @@ -48,6 +51,13 @@ public class Preferences { private static final String ENABLE_LOCATION = "enable_location"; + private static final String CALENDAR_EVENT_ID = "eventId"; + private static final String CALENDAR_EVENT_TITLE = "title"; + private static final String CALENDAR_EVENT_ALLDAY = "all_day"; + private static final String CALENDAR_EVENT_START_MILLIS = "start_millis"; + private static final String CALENDAR_EVENT_END_MILLIS = "end_millis"; + private static final String CALENDAR_EVENT_LOCATION = "location"; + private static final String CALENDAR_EVENT_COLOR = "color"; /** * User Preference related keys and constants. @@ -369,4 +379,62 @@ public class Preferences { Context context) { return getPrefs(context).getBoolean(ENABLE_LOCATION, false); } + + public static void setCachedCalendarEvents(Context context, List events) { + SharedPreferences.Editor editor = getPrefs(context).edit(); + boolean serialized = false; + if (events != null && events.size() > 0) { + JSONArray cacheList = new JSONArray(); + try { + for (CalendarEvent ev : events) { + JSONObject cacheEvent = new JSONObject(); + cacheEvent.put(CALENDAR_EVENT_ID, ev.getEventId()) + .put(CALENDAR_EVENT_TITLE, ev.getTitle()) + .put(CALENDAR_EVENT_ALLDAY, ev.isAllDay()) + .put(CALENDAR_EVENT_START_MILLIS, ev.getStartMillis()) + .put(CALENDAR_EVENT_END_MILLIS, ev.getEndMillis()) + .put(CALENDAR_EVENT_LOCATION, ev.getLocation()) + .put(CALENDAR_EVENT_COLOR, ev.getCalendarColor()); + cacheList.put(cacheEvent); + } + serialized = true; + } catch (JSONException ignored) { + // We're here because something went wrong while creating the JSON object. + // The code below will check for success and proceed accordingly + } + if (serialized) + editor.putString(Constants.CALENDAR_DATA, cacheList.toString()); + } else { + editor.remove(Constants.CALENDAR_DATA); + } + editor.apply(); + } + + public static List getCachedCalendarEvents(Context context) { + List retArray = new ArrayList<>(); + final String cachedData = getPrefs(context).getString(Constants.CALENDAR_DATA, null); + if (cachedData == null) return null; + + JSONObject last = null; + try { + JSONArray cachedEvents = new JSONArray(cachedData); + for (int indx = 0; indx < cachedEvents.length(); indx++) { + JSONObject cachedEvent = cachedEvents.getJSONObject(indx); + last = cachedEvent; + retArray.add(new CalendarEvent(context, + cachedEvent.getInt(CALENDAR_EVENT_ID), + cachedEvent.optString(CALENDAR_EVENT_TITLE, ""), + cachedEvent.getBoolean(CALENDAR_EVENT_ALLDAY), + cachedEvent.getLong(CALENDAR_EVENT_START_MILLIS), + cachedEvent.getLong(CALENDAR_EVENT_END_MILLIS), + cachedEvent.optString(CALENDAR_EVENT_LOCATION, ""), + cachedEvent.getInt(CALENDAR_EVENT_COLOR))); + } + } catch (JSONException ignored) { + Log.e("Preferences", ignored.toString()); + if(last != null) + Log.d("Preferences", last.toString()); + } + return retArray; + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 61f57ebf56..57707208d9 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,6 +32,7 @@ + + diff --git a/app/src/main/java/foundation/e/blisslauncher/core/utils/Constants.java b/app/src/main/java/foundation/e/blisslauncher/core/utils/Constants.java index 87c476a93d..2b769f06e8 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/utils/Constants.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/utils/Constants.java @@ -62,4 +62,12 @@ public class Constants { public static final int CONTAINER_DESKTOP = -100; public static final int CONTAINER_HOTSEAT = -101; + /** + * calendar widget specific + */ + public static final String CALENDAR_REFRESH_INTERVAL = "calendar_refresh_interval"; + public static final String CALENDAR_FONT_COLOR = "calendar_font_color"; + public static final String CALENDAR_ICONS = "calendar_icons"; + public static final String CALENDAR_DATA = "calendar_data"; + } diff --git a/app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarEvent.java b/app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarEvent.java new file mode 100644 index 0000000000..fe16d7f88f --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarEvent.java @@ -0,0 +1,97 @@ +package foundation.e.blisslauncher.features.calendar; + +import android.content.Context; + +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Locale; + +public class CalendarEvent { + private transient Context context; + private final int eventId; + private final String title; + private final boolean allDay; + private final Calendar startDate; + private final Calendar endDate; + private final long startMillis; + private final long endMillis; + private final String location; + private final int calendarColor; + + public void setContext(Context context) { + this.context = context; + } + + public int getEventId() { + return eventId; + } + + public String getTitle() { + return title; + } + + public boolean isAllDay() { + return allDay; + } + + public long getStartMillis() { + return startMillis; + } + + public long getEndMillis() { + return endMillis; + } + + public Calendar getStartDate() { + return startDate; + } + + public Calendar getEndDate() { + return endDate; + } + + public String getTimeFormatted() { + DateFormat dateFormat; + DateFormat timeFormat; + String formatted = null; + if (allDay) { + dateFormat = android.text.format.DateFormat.getDateFormat(context); + formatted = dateFormat.format(startMillis); + } else { + dateFormat = android.text.format.DateFormat.getDateFormat(context); + timeFormat = android.text.format.DateFormat.getTimeFormat(context); + formatted = dateFormat.format(startMillis) + " " + timeFormat.format(startMillis) + + " - " + dateFormat.format(endMillis) + " " + timeFormat.format(endMillis); + } + return formatted; + } + + public String getLocation() { + return location; + } + + public int getCalendarColor() { + return calendarColor; + } + + public CalendarEvent(Context context, int eventId, String title, boolean allDay, long startMillis, long endMillis, String location, int calendarColor) { + this.context = context; + this.eventId = eventId; + this.title = title; + this.allDay = allDay; + this.startMillis = startMillis; + this.endMillis = endMillis; + this.location = location; + this.calendarColor = calendarColor; + this.startDate = Calendar.getInstance(Locale.getDefault()); + this.endDate = Calendar.getInstance(Locale.getDefault()); + + startDate.setTimeInMillis(startMillis); + endDate.setTimeInMillis(endMillis); + } + + @Override + public String toString() { + return title + "\n" + (location != null ? (location + "\n") : "") + getTimeFormatted() + "\n"; + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarUpdateService.java b/app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarUpdateService.java new file mode 100644 index 0000000000..cd09b631d0 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/features/calendar/CalendarUpdateService.java @@ -0,0 +1,187 @@ +package foundation.e.blisslauncher.features.calendar; + +import android.Manifest; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.IBinder; +import android.provider.CalendarContract.Instances; +import android.support.annotation.Nullable; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import foundation.e.blisslauncher.core.utils.Constants; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +public class CalendarUpdateService extends Service { + private static final String TAG = "CalendarUpdateService"; + private static final boolean D = Constants.DEBUG; + + public static final String ACTION_FORCE_UPDATE = + "org.indin.blisslauncher.action.FORCE_CALENDAR_UPDATE"; + // Broadcast action for end of update + public static final String ACTION_UPDATE_FINISHED = + "org.indin.blisslauncher.action.CALENDAR_UPDATE_FINISHED"; + + + public static final String[] INSTANCE_PROJECTION = new String[]{ + Instances.EVENT_ID, // 0 + Instances.BEGIN, // 1 + Instances.END, // 2 + Instances.TITLE, // 3 + Instances.EVENT_LOCATION,// 4 + Instances.ALL_DAY, // 5 + Instances.DISPLAY_COLOR // 6 + }; + + // The indices for the projection array above. + private static final int PROJECTION_ID_INDEX = 0; + private static final int PROJECTION_BEGIN_INDEX = 1; + private static final int PROJECTION_END_INDEX = 2; + private static final int PROJECTION_TITLE_INDEX = 3; + private static final int PROJECTION_LOCATION_INDEX = 4; + private static final int PROJECTION_ALL_DAY_INDEX = 5; + private static final int PROJECTION_COLOR_INDEX = 6; + + private CalendarChangeReceiver mReceiver; + + @Override + public void onCreate() { + Log.d(TAG, "onCreate"); + + IntentFilter filter = new IntentFilter(); + filter.addAction("android.intent.action.PROVIDER_CHANGED"); + filter.addDataScheme("content"); + filter.addDataAuthority("com.android.calendar", null); + filter.setPriority(999); + mReceiver = new CalendarChangeReceiver(); + registerReceiver(mReceiver, filter); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (D) Log.v(TAG, "Got intent " + intent); + + if (!hasCalendarPermission(this)) { + Log.d(TAG, "Service started, but noc calendar permissions ... stopping"); + stopSelf(); + return START_NOT_STICKY; + } + + if (ACTION_FORCE_UPDATE.equals(intent.getAction())) { + mReceiver.updateEvents(); + } + + return START_REDELIVER_INTENT; + } + + public class CalendarChangeReceiver extends BroadcastReceiver { + // constructor + public CalendarChangeReceiver() { + + } + + @Override + public void onReceive(Context context, Intent intent) { + updateEvents(); + } + + public void updateEvents() { + List events = getUpcomingEvents(7); + foundation.e.blisslauncher.core.Preferences.setCachedCalendarEvents(getApplicationContext(), events); + Intent updateIntent = new Intent(CalendarUpdateService.ACTION_UPDATE_FINISHED); + LocalBroadcastManager.getInstance(CalendarUpdateService.this).sendBroadcast(updateIntent); + } + + private List getUpcomingEvents(int nextDays) { + List retEvents = new ArrayList<>(); + + // Load events from now to the next 7 days + Calendar beginTime = Calendar.getInstance(); + long startMillis = beginTime.getTimeInMillis(); + Calendar endTime = Calendar.getInstance(); + endTime.add(Calendar.DATE, nextDays); + long endMillis = endTime.getTimeInMillis(); + long offset = beginTime.getTimeZone().getOffset(startMillis); + + Cursor cur = null; + ContentResolver cr = getContentResolver(); + + String selection = Instances.VISIBLE + " <> 0"; + String order = Instances.BEGIN + " ASC"; + + // Construct the query with the desired date range. + Uri.Builder builder = Instances.CONTENT_URI.buildUpon(); + ContentUris.appendId(builder, startMillis); + ContentUris.appendId(builder, endMillis); + + // Submit the query + cur = cr.query(builder.build(), + INSTANCE_PROJECTION, + selection, + null, + order); + + if (cur != null && cur.getCount() > 0) { + while (cur.moveToNext()) { + int eventId = 0; + String title = null; + String location = null; + long beginVal = 0; + long endVal = 0; + boolean allDay = false; + int color = 0; + + // Get the field values + eventId = cur.getInt(PROJECTION_ID_INDEX); + beginVal = cur.getLong(PROJECTION_BEGIN_INDEX); + endVal = cur.getLong(PROJECTION_END_INDEX); + title = cur.getString(PROJECTION_TITLE_INDEX); + location = cur.getString(PROJECTION_LOCATION_INDEX); + allDay = cur.getInt(PROJECTION_ALL_DAY_INDEX) != 0; + color = cur.getInt(PROJECTION_COLOR_INDEX); + + if (allDay) { // all day events are saved in UTC not local timezone, we have to correct the values + beginVal -= offset; + endVal -= offset; + if (endVal < startMillis) + continue; + } + + CalendarEvent ev = new CalendarEvent(getApplicationContext(), eventId, title, allDay, beginVal, endVal, location, color); + retEvents.add(ev); + } + cur.close(); + } + + return retEvents; + } + } + + @Override + public void onDestroy() { + Log.d(TAG, "onDestroy"); + unregisterReceiver(mReceiver); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public static boolean hasCalendarPermission(Context context) { + return context.checkSelfPermission(Manifest.permission.READ_CALENDAR) + == PackageManager.PERMISSION_GRANTED; + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/features/calendar/EventlistBuilder.java b/app/src/main/java/foundation/e/blisslauncher/features/calendar/EventlistBuilder.java new file mode 100644 index 0000000000..74e2b161e7 --- /dev/null +++ b/app/src/main/java/foundation/e/blisslauncher/features/calendar/EventlistBuilder.java @@ -0,0 +1,142 @@ +package foundation.e.blisslauncher.features.calendar; + +import android.annotation.SuppressLint; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.net.Uri; +import android.provider.CalendarContract; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import foundation.e.blisslauncher.R; +import foundation.e.blisslauncher.core.Utilities; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; + +public class EventlistBuilder { + + private static final String TAG = "EventlistBuilder"; + + /** + * This method is used to build the small, horizontal forecasts panel + * + * @param context Context to be used + * @param smallPanel a horizontal linearlayout that will contain the forecasts + * @param events the Weather info object that contains the forecast data + */ + @SuppressLint({"InflateParams", "DefaultLocale"}) + public static void buildSmallPanel(Context context, LinearLayout smallPanel, List events) { + if (smallPanel == null) { + Log.d(TAG, "Invalid view passed"); + return; + } + try { + // Get things ready + LayoutInflater inflater + = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + smallPanel.removeAllViews(); + + Calendar date = Calendar.getInstance(); + SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy"); + String currentDate = format.format(date.getTime()); + + int day_id = 0; + + assert inflater != null; + // Load the calendar view + // create todays day layout and set the day info + View dayItem = inflater.inflate(R.layout.item_calendar_day, null); + dayItem.setTag(String.format("cal_day%d", day_id++)); + + { // don't reuse variables later.. + //setup for opening the calendar for the tapped on date + View dateIcon = dayItem.findViewById(R.id.calendar_day_date_icon); + Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon(); + builder.appendPath("time"); + ContentUris.appendId(builder, date.getTimeInMillis()); + Intent openCalendarIntent = new Intent(Intent.ACTION_VIEW) + .setData(builder.build()); + dateIcon.setOnClickListener(v -> context.startActivity(openCalendarIntent)); + } + + LinearLayout eventsList = dayItem.findViewById(R.id.calendar_day_event_list); + TextView dateView = dayItem.findViewById(R.id.calendar_day_date_textview); + TextView monthView = dayItem.findViewById(R.id.calendar_day_month_textview); + + dateView.setText(String.format(Locale.getDefault(), "%d", date.get(Calendar.DAY_OF_MONTH))); + monthView.setText(Utilities.convertMonthToString(date.get(Calendar.MONTH))); + + // Iterate through the Events + for (int count = 0; count < events.size(); count++) { + CalendarEvent event = events.get(count); + String eventDate = format.format(event.getStartMillis()); + if (!eventDate.equals(currentDate) && event.getStartMillis() >= date.getTimeInMillis()) { + currentDate = eventDate; + if (smallPanel.findViewWithTag(dayItem.getTag()) == null && dayItem.findViewWithTag("event_item") != null) { + smallPanel.addView(dayItem); + } + + // create new day layout and set the day info + dayItem = inflater.inflate(R.layout.item_calendar_day, null); + dayItem.setTag(String.format("cal_day%d", day_id++)); + + { + //setup for opening the calendar for the tapped on date + View dateIcon = dayItem.findViewById(R.id.calendar_day_date_icon); + Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon(); + builder.appendPath("time"); + ContentUris.appendId(builder, event.getStartMillis()); + Intent openCalendarIntent = new Intent(Intent.ACTION_VIEW) + .setData(builder.build()); + dateIcon.setOnClickListener(v -> context.startActivity(openCalendarIntent)); + } + + eventsList = dayItem.findViewById(R.id.calendar_day_event_list); + dateView = dayItem.findViewById(R.id.calendar_day_date_textview); + monthView = dayItem.findViewById(R.id.calendar_day_month_textview); + + dateView.setText(String.format(Locale.getDefault(), "%d", event.getStartDate().get(Calendar.DAY_OF_MONTH))); + monthView.setText(Utilities.convertMonthToString(event.getStartDate().get(Calendar.MONTH))); + } + + View eventItem = inflater.inflate(R.layout.item_calendar_event, null); + eventItem.setTag("event_item"); + + TextView title = eventItem.findViewById(R.id.calendar_event_title); + title.setText(event.getTitle()); + + TextView location = eventItem.findViewById(R.id.calendar_event_location); + if (event.getLocation() == null || event.getLocation().isEmpty()) { + location.setVisibility(View.GONE); + } else { + location.setText(event.getLocation()); + } + + TextView time = eventItem.findViewById(R.id.calendar_event_time); + time.setText(event.getTimeFormatted()); + + ImageView calendarColor = eventItem.findViewById(R.id.calendar_color); + calendarColor.setBackgroundColor(event.getCalendarColor()); + + Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, event.getEventId()); + eventItem.setOnClickListener(v -> context.startActivity(new Intent(Intent.ACTION_VIEW).setData(uri))); + eventsList.addView(eventItem); + } + if (smallPanel.findViewById(dayItem.getId()) == null) { + smallPanel.addView(dayItem); + } + } catch (Resources.NotFoundException nfe) { + nfe.printStackTrace(); + } + } +} diff --git a/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java b/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java index 3390618b31..18cfb787ec 100755 --- a/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java +++ b/app/src/main/java/foundation/e/blisslauncher/features/launcher/LauncherActivity.java @@ -113,6 +113,9 @@ import foundation.e.blisslauncher.core.utils.AppUtils; import foundation.e.blisslauncher.core.utils.Constants; import foundation.e.blisslauncher.core.utils.GraphicsUtil; import foundation.e.blisslauncher.core.utils.ListUtil; +import foundation.e.blisslauncher.features.calendar.CalendarEvent; +import foundation.e.blisslauncher.features.calendar.CalendarUpdateService; +import foundation.e.blisslauncher.features.calendar.EventlistBuilder; import foundation.e.blisslauncher.features.notification.NotificationRepository; import foundation.e.blisslauncher.features.notification.NotificationService; import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager; @@ -145,6 +148,7 @@ public class LauncherActivity extends AppCompatActivity implements private final static int INVALID = -999; private static final int REQUEST_PERMISSION_CALL_PHONE = 14; private static final int REQUEST_LOCATION_SOURCE_SETTING = 267; + private static final int REQUEST_PERMISSIONS = 1; public static boolean longPressed; private final Alarm mReorderAlarm = new Alarm(); private final Alarm mDockReorderAlarm = new Alarm(); @@ -185,6 +189,7 @@ public class LauncherActivity extends AppCompatActivity implements private BlissDragShadowBuilder dragShadowBuilder; private View mWeatherPanel; private View mWeatherSetupTextView; + private View mCalendarPanel; private boolean allAppsDisplayed; private boolean forceRefreshSuggestedApps = false; @@ -198,6 +203,15 @@ public class LauncherActivity extends AppCompatActivity implements } } }; + private BroadcastReceiver mCalendarReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + List events = Preferences.getCachedCalendarEvents(LauncherActivity.this); + if (events != null) { + updateCalendarPanel(events); + } + } + }; private FolderItem activeFolder; private BlissFrameLayout activeFolderView; private int activeDot; @@ -424,6 +438,7 @@ public class LauncherActivity extends AppCompatActivity implements EventBus.getDefault().unregister(this); unregisterReceiver(timeChangedReceiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(mWeatherReceiver); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mCalendarReceiver); getCompositeDisposable().dispose(); } @@ -715,7 +730,7 @@ public class LauncherActivity extends AppCompatActivity implements } private void updateFolderInGrid(GridLayout grid, FolderItem folderItem, - int folderIndex) { + int folderIndex) { if (folderItem.items.size() == 0) { grid.removeViewAt(folderIndex); } else { @@ -918,7 +933,7 @@ public class LauncherActivity extends AppCompatActivity implements } private void updateBadgeToApp(BlissFrameLayout viewGroup, LauncherItem appItem, - Set appsWithNotifications, boolean withText) { + Set appsWithNotifications, boolean withText) { if (appItem != null) { if (appItem.itemType == Constants.ITEM_TYPE_FOLDER) { viewGroup.applyBadge(checkHasApp((FolderItem) appItem, appsWithNotifications), @@ -1212,9 +1227,9 @@ public class LauncherActivity extends AppCompatActivity implements == AutoCompleteServiceResult.TYPE_NETWORK_ITEM) { List suggestions = new ArrayList<>(); for (int i = 0; - i < (autoCompleteServiceResults.networkItems.size() > 5 ? 5 - : autoCompleteServiceResults.networkItems.size()); - i++) { + i < (autoCompleteServiceResults.networkItems.size() > 5 ? 5 + : autoCompleteServiceResults.networkItems.size()); + i++) { suggestions.add( autoCompleteServiceResults.networkItems.get(i).getPhrase()); } @@ -1296,11 +1311,11 @@ public class LauncherActivity extends AppCompatActivity implements LocalBroadcastManager.getInstance(this).registerReceiver(mWeatherReceiver, new IntentFilter( WeatherUpdateService.ACTION_UPDATE_FINISHED)); + ArrayList permissions = new ArrayList<>(); + if (!Preferences.useCustomWeatherLocation(this)) { if (!WeatherPreferences.hasLocationPermission(this)) { - String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION}; - requestPermissions(permissions, - WeatherPreferences.LOCATION_PERMISSION_REQUEST_CODE); + permissions.add(Manifest.permission.ACCESS_FINE_LOCATION); } else { LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) @@ -1318,7 +1333,25 @@ public class LauncherActivity extends AppCompatActivity implements } // [[END]] - for (int id : mAppWidgetHost.getAppWidgetIds()) { + // Prepare calendar widget view + // [[BEGIN]] + LocalBroadcastManager.getInstance(this).registerReceiver(mCalendarReceiver, new IntentFilter( + CalendarUpdateService.ACTION_UPDATE_FINISHED)); + + if (!CalendarUpdateService.hasCalendarPermission(this)) { + permissions.add(Manifest.permission.READ_CALENDAR); + } else { + startService(new Intent(this, CalendarUpdateService.class) + .setAction(CalendarUpdateService.ACTION_FORCE_UPDATE)); + } + // [[END]] + + // if any permissions needed (currently location and calendar), we have to request them + if (!permissions.isEmpty()) { + requestPermissions(permissions.toArray(new String[0]), REQUEST_PERMISSIONS); + } + + for (int id : mAppWidgetHost.getAppWidgetIds()) { AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(id); if(appWidgetInfo != null){ RoundedWidgetView hostView = (RoundedWidgetView) mAppWidgetHost.createView( @@ -1342,19 +1375,29 @@ public class LauncherActivity extends AppCompatActivity implements @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { - if (requestCode == WeatherPreferences.LOCATION_PERMISSION_REQUEST_CODE) { + @NonNull int[] grantResults) { + if (requestCode == REQUEST_PERMISSIONS) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // We only get here if user tried to enable the preference, - // hence safe to turn it on after permission is granted - LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); - if (!lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { - showLocationEnableDialog(); - Preferences.setEnableLocation(this); - } else { - startService(new Intent(this, WeatherUpdateService.class) - .putExtra(WeatherUpdateService.ACTION_FORCE_UPDATE, true)); + for (String permission : permissions) { + switch (permission) { + case Manifest.permission.ACCESS_COARSE_LOCATION: + // We only get here if user tried to enable the preference, + // hence safe to turn it on after permission is granted + LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + if (!lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { + showLocationEnableDialog(); + Preferences.setEnableLocation(this); + } else { + startService(new Intent(this, WeatherUpdateService.class) + .putExtra(WeatherUpdateService.ACTION_FORCE_UPDATE, true)); + } + break; + case Manifest.permission.READ_CALENDAR: + startService(new Intent(this, CalendarUpdateService.class) + .setAction(CalendarUpdateService.ACTION_FORCE_UPDATE)); + break; + } } } } @@ -1395,6 +1438,20 @@ public class LauncherActivity extends AppCompatActivity implements dialog.show(); } + private void createOrUpdateCalendarPanel() { + + List events = Preferences.getCachedCalendarEvents(this); + if (events != null) { + updateCalendarPanel(events); + } + } + + private void updateCalendarPanel(List events) { + LinearLayout eventsView = findViewById(R.id.events_view); + EventlistBuilder.buildSmallPanel(this, eventsView, events); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_LOCATION_SOURCE_SETTING) { @@ -1670,7 +1727,7 @@ public class LauncherActivity extends AppCompatActivity implements } private void startShortcutIntentSafely(Context context, Intent intent, - Bundle optsBundle, LauncherItem appItem) { + Bundle optsBundle, LauncherItem appItem) { try { StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy(); try { @@ -1777,7 +1834,7 @@ public class LauncherActivity extends AppCompatActivity implements } private void makeAppWobble(BlissFrameLayout blissFrameLayout, boolean shouldPlayAnimation, - int i) { + int i) { UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); Bundle restrictions = userManager.getUserRestrictions(); boolean uninstallDisabled = restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, @@ -2479,7 +2536,7 @@ public class LauncherActivity extends AppCompatActivity implements } private void updateIcon(BlissFrameLayout appView, LauncherItem app, Drawable drawable, - boolean folderFromDock) { + boolean folderFromDock) { app.icon = drawable; List tags = (List) appView.getTag(); SquareImageView iv = (SquareImageView) tags.get(0); @@ -2593,13 +2650,13 @@ public class LauncherActivity extends AppCompatActivity implements transition.addTransitionListener(new LayoutTransition.TransitionListener() { @Override public void startTransition(LayoutTransition layoutTransition, - ViewGroup viewGroup, View view, int i) { + ViewGroup viewGroup, View view, int i) { dragDropEnabled = false; } @Override public void endTransition(LayoutTransition layoutTransition, - ViewGroup viewGroup, View view, int i) { + ViewGroup viewGroup, View view, int i) { dragDropEnabled = true; } }); @@ -2741,7 +2798,7 @@ public class LauncherActivity extends AppCompatActivity implements @Override public void destroyItem(@NonNull ViewGroup container, int position, - @NonNull Object object) { + @NonNull Object object) { container.removeView((View) object); } } diff --git a/app/src/main/res/layout/item_calendar_day.xml b/app/src/main/res/layout/item_calendar_day.xml new file mode 100644 index 0000000000..a709b2a2d2 --- /dev/null +++ b/app/src/main/res/layout/item_calendar_day.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_calendar_event.xml b/app/src/main/res/layout/item_calendar_event.xml new file mode 100644 index 0000000000..6cc5a3e0fb --- /dev/null +++ b/app/src/main/res/layout/item_calendar_event.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_calendar_info.xml b/app/src/main/res/layout/layout_calendar_info.xml new file mode 100644 index 0000000000..7301f691e6 --- /dev/null +++ b/app/src/main/res/layout/layout_calendar_info.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/widgets_page.xml b/app/src/main/res/layout/widgets_page.xml index 585d6865cc..7c99528ea4 100755 --- a/app/src/main/res/layout/widgets_page.xml +++ b/app/src/main/res/layout/widgets_page.xml @@ -61,7 +61,8 @@ - + Add to Home Screen Tap to setup App Suggestions + Upcoming Events + -- GitLab From 1f8df3b1f24e641931dae2feba9d6f00bbed5e60 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Mon, 4 Feb 2019 15:17:53 +0100 Subject: [PATCH 2/2] Fix package in resource file. --- app/src/main/res/layout/item_calendar_day.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/item_calendar_day.xml b/app/src/main/res/layout/item_calendar_day.xml index a709b2a2d2..a3816f7ca9 100644 --- a/app/src/main/res/layout/item_calendar_day.xml +++ b/app/src/main/res/layout/item_calendar_day.xml @@ -5,7 +5,7 @@ android:layout_height="wrap_content" android:orientation="horizontal"> - - +