Remove call log and sms permissions
Bug: 120483108
Test: Manual https://photos.app.goo.gl/ZkM7eyqoexYEnVzk6
Change-Id: I98f3f29c9d6da0dda1db974e599d369a5959a8c5
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4caa981..b0783d4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -46,11 +46,6 @@
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
- <!-- Following used for QuickContacts -->
- <uses-permission android:name="android.permission.READ_CALL_LOG"/>
- <uses-permission android:name="android.permission.READ_SMS"/>
- <uses-permission android:name="android.permission.READ_CALENDAR"/>
- <uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"/>
<!-- Following used for Contact metadata syncing -->
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<!-- Following used for getting the status of the contacts sync adapter -->
@@ -284,11 +279,6 @@
android:theme="@style/PeopleTheme"/>
<activity
- android:name=".activities.RequestDesiredPermissionsActivity"
- android:exported="false"
- android:theme="@style/PeopleTheme"/>
-
- <activity
android:name=".activities.RequestImportVCardPermissionsActivity"
android:exported="false"
android:theme="@style/PeopleTheme"/>
diff --git a/proguard.flags b/proguard.flags
index 07ec5d2..782aa7e 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -32,8 +32,6 @@
-keep class com.android.contacts.format.FormatUtils { *; }
-keep class com.android.contacts.format.TextHighlighter { *; }
-keep class com.android.contacts.group.GroupUtil { *; }
--keep class com.android.contacts.interactions.CallLogInteraction { *; }
--keep class com.android.contacts.interactions.CallLogInteractionsLoader { *; }
-keep class com.android.contacts.interactions.ContactDeletionInteraction { *; }
-keep class com.android.contacts.interactions.ContactInteractionUtil { *; }
-keep class com.android.contacts.list.ContactListItemView { *; }
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d461455..56c4aaa 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -584,29 +584,11 @@
<!-- Button Label to see less on an ExpandingEntryCardView [CHAR LIMIT=40] -->
<string name="expanding_entry_card_view_see_less">See less</string>
- <!-- Title of recent card. [CHAR LIMIT=60] -->
- <string name="recent_card_title">Recent</string>
-
- <!-- Title of recent card. [CHAR LIMIT=40] -->
+ <!-- Title of about card. [CHAR LIMIT=40] -->
<string name="about_card_title">About</string>
<!-- Toast that appears when you are copying a directory contact into your personal contacts -->
<string name="toast_making_personal_copy">Creating a personal copy…</string>
- <!-- Timestamp string for interactions from tomorrow. [CHAR LIMIT=40] -->
- <string name="tomorrow">Tomorrow</string>
- <!-- Timestamp string for interactions from today. [CHAR LIMIT=40] -->
- <string name="today">Today</string>
- <!-- Text for an event starting on the current day with a start and end time.
- For ex, "Today at 5:00pm-6:00pm" [CHAR LIMIT=NONE] -->
- <string name="today_at_time_fmt">"Today at <xliff:g id="time_interval">%s</xliff:g>"</string>
- <!-- Text for an event starting on the next day with a start and end time.
- For ex, "Tomorrow at 5:00pm-6:00pm" [CHAR LIMIT=NONE] -->
- <string name="tomorrow_at_time_fmt">"Tomorrow at <xliff:g id="time_interval">%s</xliff:g>"</string>
- <!-- Format string for a date and time description. For ex:
- "April 19, 2012, 3:00pm - 4:00pm" [CHAR LIMIT=NONE] -->
- <string name="date_time_fmt">"<xliff:g id="date">%1$s</xliff:g>, <xliff:g id="time_interval">%2$s</xliff:g>"</string>
- <!-- Title for untitled calendar interactions [CHAR LIMIT=40] -->
- <string name="untitled_event">(Untitled event)</string>
<!-- Name of the button in the date/time picker to accept the date/time change [CHAR LIMIT=15] -->
<string name="date_time_set">Set</string>
@@ -635,22 +617,6 @@
<!-- Content description for directions secondary button [CHAR LIMIT=NONE] -->
<string name="content_description_directions">directions to location</string>
- <!-- Content description for recent sms interaction [CHAR LIMIT=NONE] -->
- <string name="content_description_recent_sms">recent sms. <xliff:g id="message_body">%1$s</xliff:g>. <xliff:g id="phone_number">%2$s</xliff:g>. <xliff:g id="date">%3$s</xliff:g>. click to respond</string>
-
- <!-- Header for the Relation entry [CHAR LIMIT=NONE] -->
- <string name="content_description_recent_call_type_incoming">incoming</string>
- <!-- Header for the Relation entry [CHAR LIMIT=NONE] -->
- <string name="content_description_recent_call_type_outgoing">outgoing</string>
- <!-- Header for the Relation entry [CHAR LIMIT=NONE] -->
- <string name="content_description_recent_call_type_missed">missed</string>
-
- <!-- Content description for recent sms interaction [CHAR LIMIT=NONE] -->
- <string name="content_description_recent_call">recent call. <xliff:g id="call_type">%1$s</xliff:g>. <xliff:g id="phone_number">%2$s</xliff:g>. <xliff:g id="date">%3$s</xliff:g>. click to call back</string>
-
- <!-- Prefix for messages that you sent [CHAR LIMIT=40] -->
- <string name="message_from_you_prefix">You: <xliff:g id="sms_body">%s</xliff:g></string>
-
<!-- Button to expand the contact editor to show all available input fields. [CHAR LIMIT=60] -->
<string name="editor_more_fields">More fields</string>
@@ -716,22 +682,6 @@
<!-- Menu section title of "accounts" [CHAR LIMIT=20] -->
<string name="menu_title_filters">Accounts</string>
- <!-- Contacts app asking for permissions in QuickContact activity,
- in order to display calendar and SMS history [CHAR LIMIT=60] -->
- <string name="permission_explanation_header">See your history together</string>
-
- <!-- Content displayed in QuickContact activity after Contacts app receiving
- Calendar and SMS permissions [CHAR LIMIT=60] -->
- <string name="permission_explanation_subheader_calendar_and_SMS">Events and messages</string>
-
- <!-- Content displayed in QuickContact activity after Contacts app receiving
- Calendar permission [CHAR LIMIT=40] -->
- <string name="permission_explanation_subheader_calendar">Events</string>
-
- <!-- Content displayed in QuickContact activity after Contacts app receiving
- SMS permission [CHAR LIMIT=40] -->
- <string name="permission_explanation_subheader_SMS">Messages</string>
-
<!-- The header text for hamburger promo [CHAR LIMIT=60]-->
<string name="hamburger_feature_highlight_header">Suggestions</string>
<!-- The body text for hamburger promo [CHAR LIMIT=200]-->
@@ -1495,15 +1445,6 @@
<!-- Content description for (...) in no name header [CHAR LIMIT=30]-->
<string name="description_no_name_header">Ellipsis</string>
- <!-- Formatted call duration displayed in recent card in QuickContact, for duration less than 1 minute -->
- <string name="callDurationSecondFormat"><xliff:g id="seconds">%s</xliff:g> sec</string>
-
- <!-- Formatted call duration displayed in recent card in QuickContact, for duration less than 1 hour -->
- <string name="callDurationMinuteFormat"><xliff:g id="minutes">%1$s</xliff:g> min <xliff:g id="seconds">%2$s</xliff:g> sec</string>
-
- <!-- Formatted call duration displayed in recent card in QuickContact, for duration more than 1 hour -->
- <string name="callDurationHourFormat"><xliff:g id="minutes">%1$s</xliff:g> hr <xliff:g id="minutes">%2$s</xliff:g> min <xliff:g id="seconds">%3$s</xliff:g> sec</string>
-
<!-- Toast shown when a dynamic shortcut is tapped after being disabled because the experiment was turned off on the device -->
<string name="dynamic_shortcut_disabled_message">This shortcut has been disabled</string>
@@ -1592,4 +1533,4 @@
<!-- Text of Negative Button in dialog -->
<string name="no_button">No</string>
-</resources>
+</resources>
\ No newline at end of file
diff --git a/src/com/android/contacts/activities/RequestDesiredPermissionsActivity.java b/src/com/android/contacts/activities/RequestDesiredPermissionsActivity.java
deleted file mode 100644
index 0e0d5da..0000000
--- a/src/com/android/contacts/activities/RequestDesiredPermissionsActivity.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2016 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.contacts.activities;
-
-import android.Manifest.permission;
-import android.app.Activity;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Requests permissions that are not absolutely required by the calling Activity;
- * if permissions are denied, the calling Activity is still restarted.
- *
- * Activities that have a set of permissions that must be granted in order for the Activity to
- * function propertly should call
- * {@link RequestPermissionsActivity#startPermissionActivity(Activity, String[], Class)}
- * before calling {@link RequestDesiredPermissionsActivity#startPermissionActivity(Activity)}.
- */
-public class RequestDesiredPermissionsActivity extends RequestPermissionsActivityBase {
-
- private static String[] sDesiredPermissions;
-
- @Override
- protected String[] getPermissions() {
- return getPermissions(getPackageManager());
- }
-
- /**
- * If any desired permission that Contacts app needs are missing, open an Activity
- * to prompt user for these permissions. After that calling activity is restarted
- * and in the second run permission check is skipped.
- *
- * This is designed to be called inside {@link android.app.Activity#onCreate}
- */
- public static boolean startPermissionActivity(Activity activity) {
- final Bundle extras = activity.getIntent().getExtras();
- if (extras != null && extras.getBoolean(EXTRA_STARTED_PERMISSIONS_ACTIVITY, false)) {
- return false;
- }
- return startPermissionActivity(activity,
- getPermissions(activity.getPackageManager()),
- RequestDesiredPermissionsActivity.class);
- }
-
- private static String[] getPermissions(PackageManager packageManager) {
- if (sDesiredPermissions == null) {
- final List<String> permissions = new ArrayList<>();
- // Calendar group
- permissions.add(permission.READ_CALENDAR);
-
- if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- // SMS group
- permissions.add(permission.READ_SMS);
- }
- sDesiredPermissions = permissions.toArray(new String[0]);
- }
- return sDesiredPermissions;
- }
-
- @Override
- public void onRequestPermissionsResult(
- int requestCode, String permissions[], int[] grantResults) {
- mPreviousActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- startActivity(mPreviousActivityIntent);
- overridePendingTransition(0, 0);
-
- finish();
- overridePendingTransition(0, 0);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/activities/RequestPermissionsActivity.java b/src/com/android/contacts/activities/RequestPermissionsActivity.java
index e086cea..aac8a6b 100644
--- a/src/com/android/contacts/activities/RequestPermissionsActivity.java
+++ b/src/com/android/contacts/activities/RequestPermissionsActivity.java
@@ -21,11 +21,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.widget.Toast;
-
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.android.contacts.R;
-
import java.util.ArrayList;
import java.util.List;
@@ -70,7 +68,6 @@
// ImportExportDialogFragment. We work around missing this permission when
// telephony is not available on the device (i.e. on tablets).
permissions.add(permission.CALL_PHONE);
- permissions.add(permission.READ_CALL_LOG);
permissions.add(permission.READ_PHONE_STATE);
}
sRequiredPermissions = permissions.toArray(new String[0]);
diff --git a/src/com/android/contacts/interactions/CalendarInteraction.java b/src/com/android/contacts/interactions/CalendarInteraction.java
deleted file mode 100644
index 9b7ab31..0000000
--- a/src/com/android/contacts/interactions/CalendarInteraction.java
+++ /dev/null
@@ -1,288 +0,0 @@
-package com.android.contacts.interactions;
-
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.provider.CalendarContract.Attendees;
-import android.provider.CalendarContract.Events;
-import android.text.Spannable;
-import android.text.TextUtils;
-import android.text.format.Time;
-
-import com.android.contacts.R;
-
-/**
- * Represents a calendar event interaction, wrapping the columns in
- * {@link android.provider.CalendarContract.Attendees}.
- */
-public class CalendarInteraction implements ContactInteraction {
- private static final String TAG = CalendarInteraction.class.getSimpleName();
-
- private static final int CALENDAR_ICON_RES = R.drawable.quantum_ic_event_vd_theme_24;
-
- private ContentValues mValues;
-
- public CalendarInteraction(ContentValues values) {
- mValues = values;
- }
-
- @Override
- public Intent getIntent() {
- return new Intent(Intent.ACTION_VIEW).setData(
- ContentUris.withAppendedId(Events.CONTENT_URI, getEventId()));
- }
-
- @Override
- public long getInteractionDate() {
- return getDtstart();
- }
-
- @Override
- public String getViewHeader(Context context) {
- String title = getTitle();
- if (TextUtils.isEmpty(title)) {
- return context.getResources().getString(R.string.untitled_event);
- }
- return title;
- }
-
- @Override
- public String getViewBody(Context context) {
- return null;
- }
-
- @Override
- public String getViewFooter(Context context) {
- // Pulled from com.android.calendar.EventInfoFragment.updateEvent(View view)
- // TODO: build callback to update time zone if different than preferences
- String localTimezone = Time.getCurrentTimezone();
-
- Long dateEnd = getDtend();
- Long dateStart = getDtstart();
- if (dateStart == null && dateEnd == null) {
- return null;
- } else if (dateEnd == null) {
- dateEnd = dateStart;
- } else if (dateStart == null) {
- dateStart = dateEnd;
- }
-
- String displayedDatetime = CalendarInteractionUtils.getDisplayedDatetime(
- dateStart, dateEnd, System.currentTimeMillis(), localTimezone,
- getAllDay(), context);
-
- return displayedDatetime;
- }
-
- @Override
- public Drawable getIcon(Context context) {
- return context.getResources().getDrawable(CALENDAR_ICON_RES);
- }
-
- @Override
- public Drawable getBodyIcon(Context context) {
- return null;
- }
-
- @Override
- public Drawable getFooterIcon(Context context) {
- return null;
- }
-
- public String getAttendeeEmail() {
- return mValues.getAsString(Attendees.ATTENDEE_EMAIL);
- }
-
- public String getAttendeeIdentity() {
- return mValues.getAsString(Attendees.ATTENDEE_IDENTITY);
- }
-
- public String getAttendeeIdNamespace() {
- return mValues.getAsString(Attendees.ATTENDEE_ID_NAMESPACE);
- }
-
- public String getAttendeeName() {
- return mValues.getAsString(Attendees.ATTENDEE_NAME);
- }
-
- public Integer getAttendeeRelationship() {
- return mValues.getAsInteger(Attendees.ATTENDEE_RELATIONSHIP);
- }
-
- public Integer getAttendeeStatus() {
- return mValues.getAsInteger(Attendees.ATTENDEE_STATUS);
- }
-
- public Integer getAttendeeType() {
- return mValues.getAsInteger(Attendees.ATTENDEE_TYPE);
- }
-
- public Integer getEventId() {
- return mValues.getAsInteger(Attendees.EVENT_ID);
- }
-
- public Integer getAccessLevel() {
- return mValues.getAsInteger(Attendees.ACCESS_LEVEL);
- }
-
- public Boolean getAllDay() {
- return mValues.getAsInteger(Attendees.ALL_DAY) == 1 ? true : false;
- }
-
- public Integer getAvailability() {
- return mValues.getAsInteger(Attendees.AVAILABILITY);
- }
-
- public Integer getCalendarId() {
- return mValues.getAsInteger(Attendees.CALENDAR_ID);
- }
-
- public Boolean getCanInviteOthers() {
- return mValues.getAsBoolean(Attendees.CAN_INVITE_OTHERS);
- }
-
- public String getCustomAppPackage() {
- return mValues.getAsString(Attendees.CUSTOM_APP_PACKAGE);
- }
-
- public String getCustomAppUri() {
- return mValues.getAsString(Attendees.CUSTOM_APP_URI);
- }
-
- public String getDescription() {
- return mValues.getAsString(Attendees.DESCRIPTION);
- }
-
- public Integer getDisplayColor() {
- return mValues.getAsInteger(Attendees.DISPLAY_COLOR);
- }
-
- public Long getDtend() {
- return mValues.getAsLong(Attendees.DTEND);
- }
-
- public Long getDtstart() {
- return mValues.getAsLong(Attendees.DTSTART);
- }
-
- public String getDuration() {
- return mValues.getAsString(Attendees.DURATION);
- }
-
- public Integer getEventColor() {
- return mValues.getAsInteger(Attendees.EVENT_COLOR);
- }
-
- public String getEventColorKey() {
- return mValues.getAsString(Attendees.EVENT_COLOR_KEY);
- }
-
- public String getEventEndTimezone() {
- return mValues.getAsString(Attendees.EVENT_END_TIMEZONE);
- }
-
- public String getEventLocation() {
- return mValues.getAsString(Attendees.EVENT_LOCATION);
- }
-
- public String getExdate() {
- return mValues.getAsString(Attendees.EXDATE);
- }
-
- public String getExrule() {
- return mValues.getAsString(Attendees.EXRULE);
- }
-
- public Boolean getGuestsCanInviteOthers() {
- return mValues.getAsBoolean(Attendees.GUESTS_CAN_INVITE_OTHERS);
- }
-
- public Boolean getGuestsCanModify() {
- return mValues.getAsBoolean(Attendees.GUESTS_CAN_MODIFY);
- }
-
- public Boolean getGuestsCanSeeGuests() {
- return mValues.getAsBoolean(Attendees.GUESTS_CAN_SEE_GUESTS);
- }
-
- public Boolean getHasAlarm() {
- return mValues.getAsBoolean(Attendees.HAS_ALARM);
- }
-
- public Boolean getHasAttendeeData() {
- return mValues.getAsBoolean(Attendees.HAS_ATTENDEE_DATA);
- }
-
- public Boolean getHasExtendedProperties() {
- return mValues.getAsBoolean(Attendees.HAS_EXTENDED_PROPERTIES);
- }
-
- public String getIsOrganizer() {
- return mValues.getAsString(Attendees.IS_ORGANIZER);
- }
-
- public Long getLastDate() {
- return mValues.getAsLong(Attendees.LAST_DATE);
- }
-
- public Boolean getLastSynced() {
- return mValues.getAsBoolean(Attendees.LAST_SYNCED);
- }
-
- public String getOrganizer() {
- return mValues.getAsString(Attendees.ORGANIZER);
- }
-
- public Boolean getOriginalAllDay() {
- return mValues.getAsBoolean(Attendees.ORIGINAL_ALL_DAY);
- }
-
- public String getOriginalId() {
- return mValues.getAsString(Attendees.ORIGINAL_ID);
- }
-
- public Long getOriginalInstanceTime() {
- return mValues.getAsLong(Attendees.ORIGINAL_INSTANCE_TIME);
- }
-
- public String getOriginalSyncId() {
- return mValues.getAsString(Attendees.ORIGINAL_SYNC_ID);
- }
-
- public String getRdate() {
- return mValues.getAsString(Attendees.RDATE);
- }
-
- public String getRrule() {
- return mValues.getAsString(Attendees.RRULE);
- }
-
- public Integer getSelfAttendeeStatus() {
- return mValues.getAsInteger(Attendees.SELF_ATTENDEE_STATUS);
- }
-
- public Integer getStatus() {
- return mValues.getAsInteger(Attendees.STATUS);
- }
-
- public String getTitle() {
- return mValues.getAsString(Attendees.TITLE);
- }
-
- public String getUid2445() {
- return mValues.getAsString(Attendees.UID_2445);
- }
-
- @Override
- public Spannable getContentDescription(Context context) {
- // The default TalkBack is good
- return null;
- }
-
- @Override
- public int getIconResourceId() {
- return CALENDAR_ICON_RES;
- }
-}
diff --git a/src/com/android/contacts/interactions/CalendarInteractionUtils.java b/src/com/android/contacts/interactions/CalendarInteractionUtils.java
deleted file mode 100644
index 36a5621..0000000
--- a/src/com/android/contacts/interactions/CalendarInteractionUtils.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package com.android.contacts.interactions;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-
-import com.android.contacts.R;
-
-import java.util.Formatter;
-import java.util.Locale;
-
-/**
- * The following methods were pulled from
- * {@link com.android.calendar.EventInfoFragment.updateEvent(View view)}
- * TODO: Move this to frameworks/opt
- */
-public class CalendarInteractionUtils {
-
- // Using int constants as a return value instead of an enum to minimize resources.
- private static final int TODAY = 1;
- private static final int TOMORROW = 2;
- private static final int NONE = 0;
-
- /**
- * Returns a string description of the specified time interval.
- */
- public static String getDisplayedDatetime(long startMillis, long endMillis, long currentMillis,
- String localTimezone, boolean allDay, Context context) {
- // Configure date/time formatting.
- int flagsDate = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY;
- int flagsTime = DateUtils.FORMAT_SHOW_TIME;
- if (DateFormat.is24HourFormat(context)) {
- flagsTime |= DateUtils.FORMAT_24HOUR;
- }
-
- Time currentTime = new Time(localTimezone);
- currentTime.set(currentMillis);
- Resources resources = context.getResources();
- String datetimeString = null;
- if (allDay) {
- // All day events require special timezone adjustment.
- long localStartMillis = convertAlldayUtcToLocal(null, startMillis, localTimezone);
- long localEndMillis = convertAlldayUtcToLocal(null, endMillis, localTimezone);
- if (singleDayEvent(localStartMillis, localEndMillis, currentTime.gmtoff)) {
- // If possible, use "Today" or "Tomorrow" instead of a full date string.
- int todayOrTomorrow = isTodayOrTomorrow(context.getResources(),
- localStartMillis, currentMillis, currentTime.gmtoff);
- if (TODAY == todayOrTomorrow) {
- datetimeString = resources.getString(R.string.today);
- } else if (TOMORROW == todayOrTomorrow) {
- datetimeString = resources.getString(R.string.tomorrow);
- }
- }
- if (datetimeString == null) {
- // For multi-day allday events or single-day all-day events that are not
- // today or tomorrow, use framework formatter.
- Formatter f = new Formatter(new StringBuilder(50), Locale.getDefault());
- datetimeString = DateUtils.formatDateRange(context, f, startMillis,
- endMillis, flagsDate, Time.TIMEZONE_UTC).toString();
- }
- } else {
- if (singleDayEvent(startMillis, endMillis, currentTime.gmtoff)) {
- // Format the time.
- String timeString = formatDateRange(context, startMillis, endMillis,
- flagsTime);
-
- // If possible, use "Today" or "Tomorrow" instead of a full date string.
- int todayOrTomorrow = isTodayOrTomorrow(context.getResources(), startMillis,
- currentMillis, currentTime.gmtoff);
- if (TODAY == todayOrTomorrow) {
- // Example: "Today at 1:00pm - 2:00 pm"
- datetimeString = resources.getString(R.string.today_at_time_fmt,
- timeString);
- } else if (TOMORROW == todayOrTomorrow) {
- // Example: "Tomorrow at 1:00pm - 2:00 pm"
- datetimeString = resources.getString(R.string.tomorrow_at_time_fmt,
- timeString);
- } else {
- // Format the full date. Example: "Thursday, April 12, 1:00pm - 2:00pm"
- String dateString = formatDateRange(context, startMillis, endMillis,
- flagsDate);
- datetimeString = resources.getString(R.string.date_time_fmt, dateString,
- timeString);
- }
- } else {
- // For multiday events, shorten day/month names.
- // Example format: "Fri Apr 6, 5:00pm - Sun, Apr 8, 6:00pm"
- int flagsDatetime = flagsDate | flagsTime | DateUtils.FORMAT_ABBREV_MONTH |
- DateUtils.FORMAT_ABBREV_WEEKDAY;
- datetimeString = formatDateRange(context, startMillis, endMillis,
- flagsDatetime);
- }
- }
- return datetimeString;
- }
-
- /**
- * Convert given UTC time into current local time. This assumes it is for an
- * allday event and will adjust the time to be on a midnight boundary.
- *
- * @param recycle Time object to recycle, otherwise null.
- * @param utcTime Time to convert, in UTC.
- * @param tz The time zone to convert this time to.
- */
- private static long convertAlldayUtcToLocal(Time recycle, long utcTime, String tz) {
- if (recycle == null) {
- recycle = new Time();
- }
- recycle.timezone = Time.TIMEZONE_UTC;
- recycle.set(utcTime);
- recycle.timezone = tz;
- return recycle.normalize(true);
- }
-
- public static long convertAlldayLocalToUTC(Time recycle, long localTime, String tz) {
- if (recycle == null) {
- recycle = new Time();
- }
- recycle.timezone = tz;
- recycle.set(localTime);
- recycle.timezone = Time.TIMEZONE_UTC;
- return recycle.normalize(true);
- }
-
- /**
- * Returns whether the specified time interval is in a single day.
- */
- private static boolean singleDayEvent(long startMillis, long endMillis, long localGmtOffset) {
- if (startMillis == endMillis) {
- return true;
- }
-
- // An event ending at midnight should still be a single-day event, so check
- // time end-1.
- int startDay = Time.getJulianDay(startMillis, localGmtOffset);
- int endDay = Time.getJulianDay(endMillis - 1, localGmtOffset);
- return startDay == endDay;
- }
-
- /**
- * Returns TODAY or TOMORROW if applicable. Otherwise returns NONE.
- */
- private static int isTodayOrTomorrow(Resources r, long dayMillis,
- long currentMillis, long localGmtOffset) {
- int startDay = Time.getJulianDay(dayMillis, localGmtOffset);
- int currentDay = Time.getJulianDay(currentMillis, localGmtOffset);
-
- int days = startDay - currentDay;
- if (days == 1) {
- return TOMORROW;
- } else if (days == 0) {
- return TODAY;
- } else {
- return NONE;
- }
- }
-
- /**
- * Formats a date or a time range according to the local conventions.
- *
- * This formats a date/time range using Calendar's time zone and the
- * local conventions for the region of the device.
- *
- * If the {@link DateUtils#FORMAT_UTC} flag is used it will pass in
- * the UTC time zone instead.
- *
- * @param context the context is required only if the time is shown
- * @param startMillis the start time in UTC milliseconds
- * @param endMillis the end time in UTC milliseconds
- * @param flags a bit mask of options See
- * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
- * @return a string containing the formatted date/time range.
- */
- private static String formatDateRange(Context context, long startMillis,
- long endMillis, int flags) {
- String date;
- String tz;
- if ((flags & DateUtils.FORMAT_UTC) != 0) {
- tz = Time.TIMEZONE_UTC;
- } else {
- tz = Time.getCurrentTimezone();
- }
- StringBuilder sb = new StringBuilder(50);
- Formatter f = new Formatter(sb, Locale.getDefault());
- sb.setLength(0);
- date = DateUtils.formatDateRange(context, f, startMillis, endMillis, flags,
- tz).toString();
- return date;
- }
-}
diff --git a/src/com/android/contacts/interactions/CalendarInteractionsLoader.java b/src/com/android/contacts/interactions/CalendarInteractionsLoader.java
deleted file mode 100644
index 646b2db..0000000
--- a/src/com/android/contacts/interactions/CalendarInteractionsLoader.java
+++ /dev/null
@@ -1,239 +0,0 @@
-package com.android.contacts.interactions;
-
-import android.Manifest.permission;
-import android.content.AsyncTaskLoader;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.provider.CalendarContract;
-import android.provider.CalendarContract.Calendars;
-import android.util.Log;
-
-import com.android.contacts.util.PermissionsUtil;
-
-import com.google.common.base.Preconditions;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-
-/**
- * Loads a list of calendar interactions showing shared calendar events with everyone passed in
- * {@param emailAddresses}.
- *
- * Note: the calendar provider treats mailing lists as atomic email addresses.
- */
-public class CalendarInteractionsLoader extends AsyncTaskLoader<List<ContactInteraction>> {
- private static final String TAG = "CalendarInteractions";
-
- private List<String> mEmailAddresses;
- private int mMaxFutureToRetrieve;
- private int mMaxPastToRetrieve;
- private long mNumberFutureMillisecondToSearchLocalCalendar;
- private long mNumberPastMillisecondToSearchLocalCalendar;
- private List<ContactInteraction> mData;
-
-
- /**
- * @param maxFutureToRetrieve The maximum number of future events to retrieve
- * @param maxPastToRetrieve The maximum number of past events to retrieve
- */
- public CalendarInteractionsLoader(Context context, List<String> emailAddresses,
- int maxFutureToRetrieve, int maxPastToRetrieve,
- long numberFutureMillisecondToSearchLocalCalendar,
- long numberPastMillisecondToSearchLocalCalendar) {
- super(context);
- mEmailAddresses = emailAddresses;
- mMaxFutureToRetrieve = maxFutureToRetrieve;
- mMaxPastToRetrieve = maxPastToRetrieve;
- mNumberFutureMillisecondToSearchLocalCalendar =
- numberFutureMillisecondToSearchLocalCalendar;
- mNumberPastMillisecondToSearchLocalCalendar = numberPastMillisecondToSearchLocalCalendar;
- }
-
- @Override
- public List<ContactInteraction> loadInBackground() {
- if (!PermissionsUtil.hasPermission(getContext(), permission.READ_CALENDAR)
- || mEmailAddresses == null || mEmailAddresses.size() < 1) {
- return Collections.emptyList();
- }
- // Perform separate calendar queries for events in the past and future.
- Cursor cursor = getSharedEventsCursor(/* isFuture= */ true, mMaxFutureToRetrieve);
- List<ContactInteraction> interactions = getInteractionsFromEventsCursor(cursor);
- cursor = getSharedEventsCursor(/* isFuture= */ false, mMaxPastToRetrieve);
- List<ContactInteraction> interactions2 = getInteractionsFromEventsCursor(cursor);
-
- ArrayList<ContactInteraction> allInteractions = new ArrayList<ContactInteraction>(
- interactions.size() + interactions2.size());
- allInteractions.addAll(interactions);
- allInteractions.addAll(interactions2);
-
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "# ContactInteraction Loaded: " + allInteractions.size());
- }
- return allInteractions;
- }
-
- /**
- * @return events inside phone owners' calendars, that are shared with people inside mEmails
- */
- private Cursor getSharedEventsCursor(boolean isFuture, int limit) {
- List<String> calendarIds = getOwnedCalendarIds();
- if (calendarIds == null) {
- return null;
- }
- long timeMillis = System.currentTimeMillis();
-
- List<String> selectionArgs = new ArrayList<>();
- selectionArgs.addAll(mEmailAddresses);
- selectionArgs.addAll(calendarIds);
-
- // Add time constraints to selectionArgs
- String timeOperator = isFuture ? " > " : " < ";
- long pastTimeCutoff = timeMillis - mNumberPastMillisecondToSearchLocalCalendar;
- long futureTimeCutoff = timeMillis
- + mNumberFutureMillisecondToSearchLocalCalendar;
- String[] timeArguments = {String.valueOf(timeMillis), String.valueOf(pastTimeCutoff),
- String.valueOf(futureTimeCutoff)};
- selectionArgs.addAll(Arrays.asList(timeArguments));
-
- // When LAST_SYNCED = 1, the event is not a real event. We should ignore all such events.
- String IS_NOT_TEMPORARY_COPY_OF_LOCAL_EVENT
- = CalendarContract.Attendees.LAST_SYNCED + " = 0";
-
- String orderBy = CalendarContract.Attendees.DTSTART + (isFuture ? " ASC " : " DESC ");
- String selection = caseAndDotInsensitiveEmailComparisonClause(mEmailAddresses.size())
- + " AND " + CalendarContract.Attendees.CALENDAR_ID
- + " IN " + ContactInteractionUtil.questionMarks(calendarIds.size())
- + " AND " + CalendarContract.Attendees.DTSTART + timeOperator + " ? "
- + " AND " + CalendarContract.Attendees.DTSTART + " > ? "
- + " AND " + CalendarContract.Attendees.DTSTART + " < ? "
- + " AND " + IS_NOT_TEMPORARY_COPY_OF_LOCAL_EVENT;
-
- return getContext().getContentResolver().query(CalendarContract.Attendees.CONTENT_URI,
- /* projection = */ null, selection,
- selectionArgs.toArray(new String[selectionArgs.size()]),
- orderBy + " LIMIT " + limit);
- }
-
- /**
- * Returns a clause that checks whether an attendee's email is equal to one of
- * {@param count} values. The comparison is insensitive to dots and case.
- *
- * NOTE #1: This function is only needed for supporting non google accounts. For calendars
- * synced by a google account, attendee email values will be be modified by the server to ensure
- * they match an entry in contacts.google.com.
- *
- * NOTE #2: This comparison clause can result in false positives. Ex#1, test@gmail.com will
- * match test@gmailco.m. Ex#2, a.2@exchange.com will match a2@exchange.com (exchange addresses
- * should be dot sensitive). This probably isn't a large concern.
- */
- private String caseAndDotInsensitiveEmailComparisonClause(int count) {
- Preconditions.checkArgument(count > 0, "Count needs to be positive");
- final String COMPARISON
- = " REPLACE(" + CalendarContract.Attendees.ATTENDEE_EMAIL
- + ", '.', '') = REPLACE(?, '.', '') COLLATE NOCASE";
- StringBuilder sb = new StringBuilder("( " + COMPARISON);
- for (int i = 1; i < count; i++) {
- sb.append(" OR " + COMPARISON);
- }
- return sb.append(")").toString();
- }
-
- /**
- * @return A list with upto one Card. The Card contains events from {@param Cursor}.
- * Only returns unique events.
- */
- private List<ContactInteraction> getInteractionsFromEventsCursor(Cursor cursor) {
- try {
- if (cursor == null || cursor.getCount() == 0) {
- return Collections.emptyList();
- }
- Set<String> uniqueUris = new HashSet<String>();
- ArrayList<ContactInteraction> interactions = new ArrayList<ContactInteraction>();
- while (cursor.moveToNext()) {
- ContentValues values = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- CalendarInteraction calendarInteraction = new CalendarInteraction(values);
- if (!uniqueUris.contains(calendarInteraction.getIntent().getData().toString())) {
- uniqueUris.add(calendarInteraction.getIntent().getData().toString());
- interactions.add(calendarInteraction);
- }
- }
-
- return interactions;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- /**
- * @return the Ids of calendars that are owned by accounts on the phone.
- */
- private List<String> getOwnedCalendarIds() {
- String[] projection = new String[] {Calendars._ID, Calendars.CALENDAR_ACCESS_LEVEL};
- Cursor cursor = getContext().getContentResolver().query(Calendars.CONTENT_URI, projection,
- Calendars.VISIBLE + " = 1 AND " + Calendars.CALENDAR_ACCESS_LEVEL + " = ? ",
- new String[] {String.valueOf(Calendars.CAL_ACCESS_OWNER)}, null);
- try {
- if (cursor == null || cursor.getCount() < 1) {
- return null;
- }
- cursor.moveToPosition(-1);
- List<String> calendarIds = new ArrayList<>(cursor.getCount());
- while (cursor.moveToNext()) {
- calendarIds.add(String.valueOf(cursor.getInt(0)));
- }
- return calendarIds;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- @Override
- protected void onStartLoading() {
- super.onStartLoading();
-
- if (mData != null) {
- deliverResult(mData);
- }
-
- if (takeContentChanged() || mData == null) {
- forceLoad();
- }
- }
-
- @Override
- protected void onStopLoading() {
- // Attempt to cancel the current load task if possible.
- cancelLoad();
- }
-
- @Override
- protected void onReset() {
- super.onReset();
-
- // Ensure the loader is stopped
- onStopLoading();
- if (mData != null) {
- mData.clear();
- }
- }
-
- @Override
- public void deliverResult(List<ContactInteraction> data) {
- mData = data;
- if (isStarted()) {
- super.deliverResult(data);
- }
- }
-}
diff --git a/src/com/android/contacts/interactions/CallLogInteraction.java b/src/com/android/contacts/interactions/CallLogInteraction.java
deleted file mode 100644
index 8890478..0000000
--- a/src/com/android/contacts/interactions/CallLogInteraction.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2014 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.contacts.interactions;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.provider.CallLog.Calls;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.text.BidiFormatter;
-import android.text.Spannable;
-import android.text.TextDirectionHeuristics;
-
-import com.android.contacts.GeoUtil;
-import com.android.contacts.R;
-import com.android.contacts.compat.PhoneNumberUtilsCompat;
-import com.android.contacts.util.BitmapUtil;
-import com.android.contacts.util.ContactDisplayUtils;
-
-/**
- * Represents a call log event interaction, wrapping the columns in
- * {@link android.provider.CallLog.Calls}.
- *
- * This class does not return log entries related to voicemail or SIP calls. Additionally,
- * this class ignores number presentation. Number presentation affects how to identify phone
- * numbers. Since, we already know the identity of the phone number owner we can ignore number
- * presentation.
- *
- * As a result of ignoring voicemail and number presentation, we don't need to worry about API
- * version.
- */
-public class CallLogInteraction implements ContactInteraction {
-
- private static final String URI_TARGET_PREFIX = "tel:";
- private static final int CALL_LOG_ICON_RES = R.drawable.quantum_ic_phone_vd_theme_24;
- private static final int CALL_ARROW_ICON_RES = R.drawable.ic_call_arrow;
- private static BidiFormatter sBidiFormatter = BidiFormatter.getInstance();
-
- private ContentValues mValues;
-
- public CallLogInteraction(ContentValues values) {
- mValues = values;
- }
-
- @Override
- public Intent getIntent() {
- String number = getNumber();
- return number == null ? null : new Intent(Intent.ACTION_CALL).setData(
- Uri.parse(URI_TARGET_PREFIX + number));
- }
-
- @Override
- public String getViewHeader(Context context) {
- String number = mValues.getAsString(Calls.NUMBER);
- if (number != null) {
- number = PhoneNumberUtilsCompat.formatNumber(number,
- PhoneNumberUtilsCompat.normalizeNumber(number),
- GeoUtil.getCurrentCountryIso(context));
- return sBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR);
- }
- return null;
- }
-
- @Override
- public long getInteractionDate() {
- Long date = getDate();
- return date == null ? -1 : date;
- }
-
- @Override
- public String getViewBody(Context context) {
- Integer numberType = getCachedNumberType();
- if (numberType == null) {
- return null;
- }
- return Phone.getTypeLabel(context.getResources(), getCachedNumberType(),
- getCachedNumberLabel()).toString();
- }
-
- @Override
- public String getViewFooter(Context context) {
- final Long date = getDate();
- if (date != null) {
- final StringBuilder callDetail = new StringBuilder();
- callDetail.append(ContactInteractionUtil.formatDateStringFromTimestamp(date, context));
- final Long duration = getDuration();
- if (duration != null) {
- callDetail.append("\n");
- callDetail.append(ContactInteractionUtil.formatDuration(duration, context));
- }
- return callDetail.toString();
- }
- return null;
- }
-
- @Override
- public Drawable getIcon(Context context) {
- return context.getResources().getDrawable(CALL_LOG_ICON_RES);
- }
-
- @Override
- public Drawable getBodyIcon(Context context) {
- return null;
- }
-
- @Override
- public Drawable getFooterIcon(Context context) {
- Drawable callArrow = null;
- Resources res = context.getResources();
- Integer type = getType();
- if (type == null) {
- return null;
- }
- switch (type) {
- case Calls.INCOMING_TYPE:
- callArrow = res.getDrawable(CALL_ARROW_ICON_RES);
- callArrow.mutate().setColorFilter(res.getColor(R.color.call_arrow_green),
- PorterDuff.Mode.MULTIPLY);
- break;
- case Calls.MISSED_TYPE:
- callArrow = res.getDrawable(CALL_ARROW_ICON_RES);
- callArrow.mutate().setColorFilter(res.getColor(R.color.call_arrow_red),
- PorterDuff.Mode.MULTIPLY);
- break;
- case Calls.OUTGOING_TYPE:
- callArrow = BitmapUtil.getRotatedDrawable(res, CALL_ARROW_ICON_RES, 180f);
- callArrow.setColorFilter(res.getColor(R.color.call_arrow_green),
- PorterDuff.Mode.MULTIPLY);
- break;
- }
- return callArrow;
- }
-
- public String getCachedName() {
- return mValues.getAsString(Calls.CACHED_NAME);
- }
-
- public String getCachedNumberLabel() {
- return mValues.getAsString(Calls.CACHED_NUMBER_LABEL);
- }
-
- public Integer getCachedNumberType() {
- return mValues.getAsInteger(Calls.CACHED_NUMBER_TYPE);
- }
-
- public Long getDate() {
- return mValues.getAsLong(Calls.DATE);
- }
-
- public Long getDuration() {
- return mValues.getAsLong(Calls.DURATION);
- }
-
- public Boolean getIsRead() {
- return mValues.getAsBoolean(Calls.IS_READ);
- }
-
- public Integer getLimitParamKey() {
- return mValues.getAsInteger(Calls.LIMIT_PARAM_KEY);
- }
-
- public Boolean getNew() {
- return mValues.getAsBoolean(Calls.NEW);
- }
-
- public String getNumber() {
- final String number = mValues.getAsString(Calls.NUMBER);
- return number == null ? null :
- sBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR);
- }
-
- public Integer getNumberPresentation() {
- return mValues.getAsInteger(Calls.NUMBER_PRESENTATION);
- }
-
- public Integer getOffsetParamKey() {
- return mValues.getAsInteger(Calls.OFFSET_PARAM_KEY);
- }
-
- public Integer getType() {
- return mValues.getAsInteger(Calls.TYPE);
- }
-
- @Override
- public Spannable getContentDescription(Context context) {
- final String phoneNumber = getViewHeader(context);
- final String contentDescription = context.getResources().getString(
- R.string.content_description_recent_call,
- getCallTypeString(context), phoneNumber, getViewFooter(context));
- return ContactDisplayUtils.getTelephoneTtsSpannable(contentDescription, phoneNumber);
- }
-
- private String getCallTypeString(Context context) {
- String callType = "";
- Resources res = context.getResources();
- Integer type = getType();
- if (type == null) {
- return callType;
- }
- switch (type) {
- case Calls.INCOMING_TYPE:
- callType = res.getString(R.string.content_description_recent_call_type_incoming);
- break;
- case Calls.MISSED_TYPE:
- callType = res.getString(R.string.content_description_recent_call_type_missed);
- break;
- case Calls.OUTGOING_TYPE:
- callType = res.getString(R.string.content_description_recent_call_type_outgoing);
- break;
- }
- return callType;
- }
-
- @Override
- public int getIconResourceId() {
- return CALL_LOG_ICON_RES;
- }
-}
diff --git a/src/com/android/contacts/interactions/CallLogInteractionsLoader.java b/src/com/android/contacts/interactions/CallLogInteractionsLoader.java
deleted file mode 100644
index 8813ecc..0000000
--- a/src/com/android/contacts/interactions/CallLogInteractionsLoader.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2014 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.contacts.interactions;
-
-import android.content.AsyncTaskLoader;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.net.Uri;
-import android.provider.CallLog.Calls;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.contacts.compat.PhoneNumberUtilsCompat;
-import com.android.contacts.util.PermissionsUtil;
-
-import com.google.common.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public class CallLogInteractionsLoader extends AsyncTaskLoader<List<ContactInteraction>> {
-
- private static final String TAG = "CallLogInteractions";
-
- private final String[] mPhoneNumbers;
- private final String[] mSipNumbers;
- private final int mMaxToRetrieve;
- private List<ContactInteraction> mData;
-
- public CallLogInteractionsLoader(Context context, String[] phoneNumbers, String[] sipNumbers,
- int maxToRetrieve) {
- super(context);
- mPhoneNumbers = phoneNumbers;
- mSipNumbers = sipNumbers;
- mMaxToRetrieve = maxToRetrieve;
- }
-
- @Override
- public List<ContactInteraction> loadInBackground() {
- final boolean hasPhoneNumber = mPhoneNumbers != null && mPhoneNumbers.length > 0;
- final boolean hasSipNumber = mSipNumbers != null && mSipNumbers.length > 0;
- if (!PermissionsUtil.hasPhonePermissions(getContext())
- || !getContext().getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
- || (!hasPhoneNumber && !hasSipNumber) || mMaxToRetrieve <= 0) {
- return Collections.emptyList();
- }
-
- final List<ContactInteraction> interactions = new ArrayList<>();
- if (hasPhoneNumber) {
- for (String number : mPhoneNumbers) {
- final String normalizedNumber = PhoneNumberUtilsCompat.normalizeNumber(number);
- if (!TextUtils.isEmpty(normalizedNumber)) {
- interactions.addAll(getCallLogInteractions(normalizedNumber));
- }
- }
- }
- if (hasSipNumber) {
- for (String number : mSipNumbers) {
- interactions.addAll(getCallLogInteractions(number));
- }
- }
-
- // Sort the call log interactions by date for duplicate removal
- Collections.sort(interactions, new Comparator<ContactInteraction>() {
- @Override
- public int compare(ContactInteraction i1, ContactInteraction i2) {
- if (i2.getInteractionDate() - i1.getInteractionDate() > 0) {
- return 1;
- } else if (i2.getInteractionDate() == i1.getInteractionDate()) {
- return 0;
- } else {
- return -1;
- }
- }
- });
- // Duplicates only occur because of fuzzy matching. No need to dedupe a single number.
- if ((hasPhoneNumber && mPhoneNumbers.length == 1 && !hasSipNumber)
- || (hasSipNumber && mSipNumbers.length == 1 && !hasPhoneNumber)) {
- return interactions;
- }
- return pruneDuplicateCallLogInteractions(interactions, mMaxToRetrieve);
- }
-
- /**
- * Two different phone numbers can match the same call log entry (since phone number
- * matching is inexact). Therefore, we need to remove duplicates. In a reasonable call log,
- * every entry should have a distinct date. Therefore, we can assume duplicate entries are
- * adjacent entries.
- * @param interactions The interaction list potentially containing duplicates
- * @return The list with duplicates removed
- */
- @VisibleForTesting
- static List<ContactInteraction> pruneDuplicateCallLogInteractions(
- List<ContactInteraction> interactions, int maxToRetrieve) {
- final List<ContactInteraction> subsetInteractions = new ArrayList<>();
- for (int i = 0; i < interactions.size(); i++) {
- if (i >= 1 && interactions.get(i).getInteractionDate() ==
- interactions.get(i-1).getInteractionDate()) {
- continue;
- }
- subsetInteractions.add(interactions.get(i));
- if (subsetInteractions.size() >= maxToRetrieve) {
- break;
- }
- }
- return subsetInteractions;
- }
-
- private List<ContactInteraction> getCallLogInteractions(String phoneNumber) {
- final Uri uri = Uri.withAppendedPath(Calls.CONTENT_FILTER_URI,
- Uri.encode(phoneNumber));
- // Append the LIMIT clause onto the ORDER BY clause. This won't cause crashes as long
- // as we don't also set the {@link android.provider.CallLog.Calls.LIMIT_PARAM_KEY} that
- // becomes available in KK.
- final String orderByAndLimit = Calls.DATE + " DESC LIMIT " + mMaxToRetrieve;
- Cursor cursor = null;
- try {
- cursor = getContext().getContentResolver().query(uri, null, null, null,
- orderByAndLimit);
- } catch (Exception e) {
- Log.e(TAG, "Can not query calllog", e);
- }
- try {
- if (cursor == null || cursor.getCount() < 1) {
- return Collections.emptyList();
- }
- cursor.moveToPosition(-1);
- List<ContactInteraction> interactions = new ArrayList<>();
- while (cursor.moveToNext()) {
- final ContentValues values = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- interactions.add(new CallLogInteraction(values));
- }
- return interactions;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- @Override
- protected void onStartLoading() {
- super.onStartLoading();
-
- if (mData != null) {
- deliverResult(mData);
- }
-
- if (takeContentChanged() || mData == null) {
- forceLoad();
- }
- }
-
- @Override
- protected void onStopLoading() {
- // Attempt to cancel the current load task if possible.
- cancelLoad();
- }
-
- @Override
- public void deliverResult(List<ContactInteraction> data) {
- mData = data;
- if (isStarted()) {
- super.deliverResult(data);
- }
- }
-
- @Override
- protected void onReset() {
- super.onReset();
-
- // Ensure the loader is stopped
- onStopLoading();
- if (mData != null) {
- mData.clear();
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/interactions/ContactInteraction.java b/src/com/android/contacts/interactions/ContactInteraction.java
deleted file mode 100644
index 6bca0af..0000000
--- a/src/com/android/contacts/interactions/ContactInteraction.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 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.contacts.interactions;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.text.Spannable;
-
-/**
- * Represents a default interaction between the phone's owner and a contact
- */
-public interface ContactInteraction {
- Intent getIntent();
- long getInteractionDate();
- String getViewHeader(Context context);
- String getViewBody(Context context);
- String getViewFooter(Context context);
- Drawable getIcon(Context context);
- Drawable getBodyIcon(Context context);
- Drawable getFooterIcon(Context context);
- Spannable getContentDescription(Context context);
- /** The resource id for the icon, if available. May be 0 if one is not available. */
- int getIconResourceId();
-}
diff --git a/src/com/android/contacts/interactions/ContactInteractionUtil.java b/src/com/android/contacts/interactions/ContactInteractionUtil.java
index e7a7a6d..daeadef 100644
--- a/src/com/android/contacts/interactions/ContactInteractionUtil.java
+++ b/src/com/android/contacts/interactions/ContactInteractionUtil.java
@@ -15,16 +15,8 @@
*/
package com.android.contacts.interactions;
-import android.content.Context;
-import android.text.format.DateUtils;
-
-import com.android.contacts.R;
-
import com.google.common.base.Preconditions;
-import java.text.DateFormat;
-import java.util.Calendar;
-
/**
* Utility methods for interactions and their loaders
*/
@@ -41,61 +33,4 @@
}
return sb.append(")").toString();
}
-
- /**
- * Same as {@link formatDateStringFromTimestamp(long, Context, Calendar)} but uses the current
- * time.
- */
- public static String formatDateStringFromTimestamp(long timestamp, Context context) {
- return formatDateStringFromTimestamp(timestamp, context, Calendar.getInstance());
- }
-
- /**
- * Takes in a timestamp and outputs a human legible date. This checks the timestamp against
- * compareCalendar.
- * This formats the date based on a few conditions:
- * 1. If the timestamp is today, the time is shown
- * 2. Otherwise show full date and time
- */
- public static String formatDateStringFromTimestamp(long timestamp, Context context,
- Calendar compareCalendar) {
- Calendar interactionCalendar = Calendar.getInstance();
- interactionCalendar.setTimeInMillis(timestamp);
-
- // compareCalendar is initialized to today
- if (compareCalendarDayYear(interactionCalendar, compareCalendar)) {
- return DateFormat.getTimeInstance(DateFormat.SHORT).format(
- interactionCalendar.getTime());
- }
-
- return DateUtils.formatDateTime(context, timestamp, DateUtils.FORMAT_SHOW_TIME
- | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
- | DateUtils.FORMAT_SHOW_YEAR);
- }
-
- /**
- * Compares the day and year of two calendars.
- */
- private static boolean compareCalendarDayYear(Calendar c1, Calendar c2) {
- return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) &&
- c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
- }
-
- /**
- * Takes duration of the call in seconds.
- * Return the formatted duration in hr, min, sec order if they exist.
- */
- public static String formatDuration(long callDuration, Context context) {
- final int hours = (int) callDuration / 3600;
- final int minutes = (int) (callDuration % 3600) / 60;
- final int seconds = (int) (callDuration % 60);
-
- if (hours > 0) {
- return context.getString(R.string.callDurationHourFormat, hours, minutes, seconds);
- } else if (minutes > 0) {
- return context.getString(R.string.callDurationMinuteFormat, minutes, seconds);
- } else {
- return context.getString(R.string.callDurationSecondFormat, seconds);
- }
- }
}
diff --git a/src/com/android/contacts/interactions/SmsInteraction.java b/src/com/android/contacts/interactions/SmsInteraction.java
deleted file mode 100644
index 4aad07b..0000000
--- a/src/com/android/contacts/interactions/SmsInteraction.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2014 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.contacts.interactions;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.provider.Telephony.Sms;
-import android.text.BidiFormatter;
-import android.text.Spannable;
-import android.text.TextDirectionHeuristics;
-
-import com.android.contacts.R;
-import com.android.contacts.util.ContactDisplayUtils;
-
-/**
- * Represents an sms interaction, wrapping the columns in
- * {@link android.provider.Telephony.Sms}.
- */
-public class SmsInteraction implements ContactInteraction {
-
- private static final String URI_TARGET_PREFIX = "smsto:";
- private static final int SMS_ICON_RES = R.drawable.quantum_ic_message_vd_theme_24;
- private static BidiFormatter sBidiFormatter = BidiFormatter.getInstance();
-
- private ContentValues mValues;
-
- public SmsInteraction(ContentValues values) {
- mValues = values;
- }
-
- @Override
- public Intent getIntent() {
- String address = getAddress();
- return address == null ? null : new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse(URI_TARGET_PREFIX + address));
- }
-
- @Override
- public long getInteractionDate() {
- Long date = getDate();
- return date == null ? -1 : date;
- }
-
- @Override
- public String getViewHeader(Context context) {
- String body = getBody();
- if (getType() == Sms.MESSAGE_TYPE_SENT) {
- body = context.getResources().getString(R.string.message_from_you_prefix, body);
- }
- return body;
- }
-
- @Override
- public String getViewBody(Context context) {
- return getAddress();
- }
-
- @Override
- public String getViewFooter(Context context) {
- Long date = getDate();
- return date == null ? null : ContactInteractionUtil.formatDateStringFromTimestamp(
- date, context);
- }
-
- @Override
- public Drawable getIcon(Context context) {
- return context.getResources().getDrawable(SMS_ICON_RES);
- }
-
- @Override
- public Drawable getBodyIcon(Context context) {
- return null;
- }
-
- @Override
- public Drawable getFooterIcon(Context context) {
- return null;
- }
-
- public String getAddress() {
- final String address = mValues.getAsString(Sms.ADDRESS);
- return address == null ? null :
- sBidiFormatter.unicodeWrap(address, TextDirectionHeuristics.LTR);
- }
-
- public String getBody() {
- return mValues.getAsString(Sms.BODY);
- }
-
- public Long getDate() {
- return mValues.getAsLong(Sms.DATE);
- }
-
-
- public Long getDateSent() {
- return mValues.getAsLong(Sms.DATE_SENT);
- }
-
- public Integer getErrorCode() {
- return mValues.getAsInteger(Sms.ERROR_CODE);
- }
-
- public Boolean getLocked() {
- return mValues.getAsBoolean(Sms.LOCKED);
- }
-
- public Integer getPerson() {
- return mValues.getAsInteger(Sms.PERSON);
- }
-
- public Integer getProtocol() {
- return mValues.getAsInteger(Sms.PROTOCOL);
- }
-
- public Boolean getRead() {
- return mValues.getAsBoolean(Sms.READ);
- }
-
- public Boolean getReplyPathPresent() {
- return mValues.getAsBoolean(Sms.REPLY_PATH_PRESENT);
- }
-
- public Boolean getSeen() {
- return mValues.getAsBoolean(Sms.SEEN);
- }
-
- public String getServiceCenter() {
- return mValues.getAsString(Sms.SERVICE_CENTER);
- }
-
- public Integer getStatus() {
- return mValues.getAsInteger(Sms.STATUS);
- }
-
- public String getSubject() {
- return mValues.getAsString(Sms.SUBJECT);
- }
-
- public Integer getThreadId() {
- return mValues.getAsInteger(Sms.THREAD_ID);
- }
-
- public Integer getType() {
- return mValues.getAsInteger(Sms.TYPE);
- }
-
- @Override
- public Spannable getContentDescription(Context context) {
- final String phoneNumber = getViewBody(context);
- final String contentDescription = context.getResources().getString(
- R.string.content_description_recent_sms,
- getViewHeader(context), phoneNumber, getViewFooter(context));
- return ContactDisplayUtils.getTelephoneTtsSpannable(contentDescription, phoneNumber);
- }
-
- @Override
- public int getIconResourceId() {
- return SMS_ICON_RES;
- }
-}
diff --git a/src/com/android/contacts/interactions/SmsInteractionsLoader.java b/src/com/android/contacts/interactions/SmsInteractionsLoader.java
deleted file mode 100644
index 31ab831..0000000
--- a/src/com/android/contacts/interactions/SmsInteractionsLoader.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2014 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.contacts.interactions;
-
-import android.content.AsyncTaskLoader;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.provider.Telephony;
-import android.util.Log;
-
-import com.android.contacts.compat.TelephonyThreadsCompat;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Loads the most recent sms between the passed in phone numbers.
- *
- * This is a two part process. The first step is retrieving the threadIds for each of the phone
- * numbers using fuzzy matching. The next step is to run another query against these threadIds
- * to retrieve the actual sms.
- */
-public class SmsInteractionsLoader extends AsyncTaskLoader<List<ContactInteraction>> {
-
- private static final String TAG = SmsInteractionsLoader.class.getSimpleName();
-
- private String[] mPhoneNums;
- private int mMaxToRetrieve;
- private List<ContactInteraction> mData;
-
- /**
- * Loads a list of SmsInteraction from the supplied phone numbers.
- */
- public SmsInteractionsLoader(Context context, String[] phoneNums,
- int maxToRetrieve) {
- super(context);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "SmsInteractionsLoader");
- }
- mPhoneNums = phoneNums;
- mMaxToRetrieve = maxToRetrieve;
- }
-
- @Override
- public List<ContactInteraction> loadInBackground() {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "loadInBackground");
- }
- // Confirm the device has Telephony and numbers were provided before proceeding
- if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
- || mPhoneNums == null || mPhoneNums.length == 0) {
- return Collections.emptyList();
- }
-
- // Retrieve the thread IDs
- List<String> threadIdStrings = new ArrayList<>();
- for (String phone : mPhoneNums) {
- // TODO: the phone numbers added to the ContactInteraction result should retain their
- // original formatting since TalkBack is not reading the normalized numbers correctly
- try {
- threadIdStrings.add(String.valueOf(
- TelephonyThreadsCompat.getOrCreateThreadId(getContext(), phone)));
- } catch (Exception e) {
- // Do nothing. Telephony.Threads.getOrCreateThreadId() throws exceptions when
- // it can't find/create a threadId (b/17657656).
- }
- }
-
- // Query the SMS database for the threads
- Cursor cursor = getSmsCursorFromThreads(threadIdStrings);
- if (cursor != null) {
- try {
- List<ContactInteraction> interactions = new ArrayList<>();
- while (cursor.moveToNext()) {
- ContentValues values = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- interactions.add(new SmsInteraction(values));
- }
-
- return interactions;
- } finally {
- cursor.close();
- }
- }
-
- return Collections.emptyList();
- }
-
- /**
- * Return the most recent messages between a list of threads
- */
- private Cursor getSmsCursorFromThreads(List<String> threadIds) {
- if (threadIds.size() == 0) {
- return null;
- }
- String selection = Telephony.Sms.THREAD_ID + " IN "
- + ContactInteractionUtil.questionMarks(threadIds.size());
-
- return getContext().getContentResolver().query(
- Telephony.Sms.CONTENT_URI,
- /* projection = */ null,
- selection,
- threadIds.toArray(new String[threadIds.size()]),
- Telephony.Sms.DEFAULT_SORT_ORDER
- + " LIMIT " + mMaxToRetrieve);
- }
-
- @Override
- protected void onStartLoading() {
- super.onStartLoading();
-
- if (mData != null) {
- deliverResult(mData);
- }
-
- if (takeContentChanged() || mData == null) {
- forceLoad();
- }
- }
-
- @Override
- protected void onStopLoading() {
- // Attempt to cancel the current load task if possible.
- cancelLoad();
- }
-
- @Override
- public void deliverResult(List<ContactInteraction> data) {
- mData = data;
- if (isStarted()) {
- super.deliverResult(data);
- }
- }
-
- @Override
- protected void onReset() {
- super.onReset();
-
- // Ensure the loader is stopped
- onStopLoading();
- if (mData != null) {
- mData.clear();
- }
- }
-}
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index df08112..51762f4 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -17,7 +17,6 @@
package com.android.contacts.quickcontact;
-import android.Manifest;
import android.accounts.Account;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
@@ -74,11 +73,6 @@
import android.provider.ContactsContract.Intents;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.RawContacts;
-import androidx.core.app.ActivityCompat;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-import androidx.core.content.res.ResourcesCompat;
-import androidx.core.os.BuildCompat;
-import androidx.palette.graphics.Palette;
import android.telecom.PhoneAccount;
import android.telecom.TelecomManager;
import android.text.BidiFormatter;
@@ -99,7 +93,10 @@
import android.view.WindowManager;
import android.widget.Toast;
import android.widget.Toolbar;
-
+import androidx.core.content.res.ResourcesCompat;
+import androidx.core.os.BuildCompat;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.palette.graphics.Palette;
import com.android.contacts.CallUtil;
import com.android.contacts.ClipboardUtils;
import com.android.contacts.Collapser;
@@ -113,7 +110,6 @@
import com.android.contacts.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
import com.android.contacts.activities.ContactEditorActivity;
import com.android.contacts.activities.ContactSelectionActivity;
-import com.android.contacts.activities.RequestDesiredPermissionsActivity;
import com.android.contacts.activities.RequestPermissionsActivity;
import com.android.contacts.compat.CompatUtils;
import com.android.contacts.compat.EventCompat;
@@ -123,11 +119,7 @@
import com.android.contacts.editor.ContactEditorFragment;
import com.android.contacts.editor.EditorIntents;
import com.android.contacts.editor.EditorUiUtils;
-import com.android.contacts.interactions.CalendarInteractionsLoader;
-import com.android.contacts.interactions.CallLogInteractionsLoader;
import com.android.contacts.interactions.ContactDeletionInteraction;
-import com.android.contacts.interactions.ContactInteraction;
-import com.android.contacts.interactions.SmsInteractionsLoader;
import com.android.contacts.interactions.TouchPointManager;
import com.android.contacts.lettertiles.LetterTileDrawable;
import com.android.contacts.list.UiIntentActions;
@@ -166,7 +158,6 @@
import com.android.contacts.util.ImplicitIntentsUtil;
import com.android.contacts.util.MaterialColorMapUtils;
import com.android.contacts.util.MaterialColorMapUtils.MaterialPalette;
-import com.android.contacts.util.PermissionsUtil;
import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.SchedulingUtils;
import com.android.contacts.util.SharedPreferenceUtil;
@@ -177,11 +168,8 @@
import com.android.contacts.widget.MultiShrinkScroller.MultiShrinkScrollerListener;
import com.android.contacts.widget.QuickContactImageView;
import com.android.contactsbind.HelpUtils;
-
import com.google.common.collect.Lists;
-
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
@@ -189,7 +177,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
/**
* Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
@@ -231,6 +218,8 @@
private static final String MIMETYPE_SMS = "vnd.android-dir/mms-sms";
private static final int REQUEST_CODE_JOIN = 3;
private static final int REQUEST_CODE_PICK_RINGTONE = 4;
+ private static final int CARD_ENTRY_ID_EDIT_CONTACT = -2;
+ private static final int MIN_NUM_CONTACT_ENTRIES_SHOWN = 3;
private static final int CURRENT_API_VERSION = android.os.Build.VERSION.SDK_INT;
@@ -261,6 +250,8 @@
private static final String HANGOUTS_DATA_5_MESSAGE = "conversation";
private static final String CALL_ORIGIN_QUICK_CONTACTS_ACTIVITY =
"com.android.contacts.quickcontact.QuickContactActivity";
+ private static final String KEY_LOADER_EXTRA_EMAILS =
+ QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_EMAILS";
// Set true in {@link #onCreate} after orientation change for later use in processIntent().
private boolean mIsRecreatedInstance;
@@ -290,18 +281,12 @@
private QuickContactImageView mPhotoView;
private ExpandingEntryCardView mContactCard;
private ExpandingEntryCardView mNoContactDetailsCard;
- private ExpandingEntryCardView mRecentCard;
private ExpandingEntryCardView mAboutCard;
- private ExpandingEntryCardView mPermissionExplanationCard;
private long mPreviousContactId = 0;
- // Permission explanation card.
- private boolean mShouldShowPermissionExplanation = false;
- private String mPermissionExplanationCardSubHeader = "";
private MultiShrinkScroller mScroller;
private AsyncTask<Void, Void, Cp2DataCardModel> mEntriesAndActionsTask;
- private AsyncTask<Void, Void, Void> mRecentDataTask;
/**
* The last copy of Cp2DataCardModel that was passed to {@link #populateContactAndAboutCard}.
@@ -361,45 +346,11 @@
/** Id for the background contact loader */
private static final int LOADER_CONTACT_ID = 0;
- /** Id for the background Sms Loader */
- private static final int LOADER_SMS_ID = 1;
- private static final int MAX_SMS_RETRIEVE = 3;
-
- /** Id for the back Calendar Loader */
- private static final int LOADER_CALENDAR_ID = 2;
- private static final String KEY_LOADER_EXTRA_EMAILS =
- QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_EMAILS";
- private static final int MAX_PAST_CALENDAR_RETRIEVE = 3;
- private static final int MAX_FUTURE_CALENDAR_RETRIEVE = 3;
- private static final long PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
- 1L * 24L * 60L * 60L * 1000L /* 1 day */;
- private static final long FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
- 7L * 24L * 60L * 60L * 1000L /* 7 days */;
-
- /** Id for the background Call Log Loader */
- private static final int LOADER_CALL_LOG_ID = 3;
- private static final int MAX_CALL_LOG_RETRIEVE = 3;
- private static final int MIN_NUM_CONTACT_ENTRIES_SHOWN = 3;
- private static final int MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN = 3;
- private static final int CARD_ENTRY_ID_EDIT_CONTACT = -2;
- private static final int CARD_ENTRY_ID_REQUEST_PERMISSION = -3;
private static final String KEY_LOADER_EXTRA_PHONES =
QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_PHONES";
private static final String KEY_LOADER_EXTRA_SIP_NUMBERS =
QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_SIP_NUMBERS";
- private static final int[] mRecentLoaderIds = new int[]{
- LOADER_SMS_ID,
- LOADER_CALENDAR_ID,
- LOADER_CALL_LOG_ID};
- /**
- * ConcurrentHashMap constructor params: 4 is initial table size, 0.9f is
- * load factor before resizing, 1 means we only expect a single thread to
- * write to the map so make only a single shard
- */
- private Map<Integer, List<ContactInteraction>> mRecentLoaderResults =
- new ConcurrentHashMap<>(4, 0.9f, 1);
-
private static final String FRAGMENT_TAG_SELECT_ACCOUNT = "select_account_fragment";
final OnClickListener mEntryClickHandler = new OnClickListener() {
@@ -419,13 +370,6 @@
return;
}
- if (dataId == CARD_ENTRY_ID_REQUEST_PERMISSION) {
- finish();
- RequestDesiredPermissionsActivity.startPermissionActivity(
- QuickContactActivity.this);
- return;
- }
-
// Pass the touch point through the intent for use in the InCallUI
if (Intent.ACTION_CALL.equals(intent.getAction())) {
if (TouchPointManager.getInstance().hasValidPoint()) {
@@ -760,43 +704,6 @@
mShouldLog = true;
- // There're 3 states for each permission:
- // 1. App doesn't have permission, not asked user yet.
- // 2. App doesn't have permission, user denied it previously.
- // 3. App has permission.
- // Permission explanation card is displayed only for case 1.
- final boolean hasTelephonyFeature =
- getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-
- final boolean hasCalendarPermission = PermissionsUtil.hasPermission(
- this, Manifest.permission.READ_CALENDAR);
- final boolean hasSMSPermission = hasTelephonyFeature
- && PermissionsUtil.hasPermission(this, Manifest.permission.READ_SMS);
-
- final boolean wasCalendarPermissionDenied =
- ActivityCompat.shouldShowRequestPermissionRationale(
- this, Manifest.permission.READ_CALENDAR);
- final boolean wasSMSPermissionDenied =
- hasTelephonyFeature && ActivityCompat.shouldShowRequestPermissionRationale(
- this, Manifest.permission.READ_SMS);
-
- final boolean shouldDisplayCalendarMessage =
- !hasCalendarPermission && !wasCalendarPermissionDenied;
- final boolean shouldDisplaySMSMessage =
- hasTelephonyFeature && !hasSMSPermission && !wasSMSPermissionDenied;
- mShouldShowPermissionExplanation = shouldDisplayCalendarMessage || shouldDisplaySMSMessage;
-
- if (shouldDisplayCalendarMessage && shouldDisplaySMSMessage) {
- mPermissionExplanationCardSubHeader =
- getString(R.string.permission_explanation_subheader_calendar_and_SMS);
- } else if (shouldDisplayCalendarMessage) {
- mPermissionExplanationCardSubHeader =
- getString(R.string.permission_explanation_subheader_calendar);
- } else if (shouldDisplaySMSMessage) {
- mPermissionExplanationCardSubHeader =
- getString(R.string.permission_explanation_subheader_SMS);
- }
-
final int previousScreenType = getIntent().getIntExtra
(EXTRA_PREVIOUS_SCREEN_TYPE, ScreenType.UNKNOWN);
Logger.logScreenView(this, ScreenType.QUICK_CONTACT, previousScreenType);
@@ -825,19 +732,12 @@
mContactCard = (ExpandingEntryCardView) findViewById(R.id.communication_card);
mNoContactDetailsCard = (ExpandingEntryCardView) findViewById(R.id.no_contact_data_card);
- mRecentCard = (ExpandingEntryCardView) findViewById(R.id.recent_card);
mAboutCard = (ExpandingEntryCardView) findViewById(R.id.about_card);
- mPermissionExplanationCard =
- (ExpandingEntryCardView) findViewById(R.id.permission_explanation_card);
- mPermissionExplanationCard.setOnClickListener(mEntryClickHandler);
mNoContactDetailsCard.setOnClickListener(mEntryClickHandler);
mContactCard.setOnClickListener(mEntryClickHandler);
mContactCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
- mRecentCard.setOnClickListener(mEntryClickHandler);
- mRecentCard.setTitle(getResources().getString(R.string.recent_card_title));
-
mAboutCard.setOnClickListener(mEntryClickHandler);
mAboutCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
@@ -1026,7 +926,6 @@
mShouldLog = true;
// After copying a directory contact, the contact URI changes. Therefore,
// we need to reload the new contact.
- destroyInteractionLoaders();
mContactLoader = (ContactLoader) (Loader<?>) getLoaderManager().getLoader(
LOADER_CONTACT_ID);
mContactLoader.setNewLookup(mLookupUri);
@@ -1035,12 +934,6 @@
mContactLoader.forceLoad();
}
- private void destroyInteractionLoaders() {
- for (int interactionLoaderId : mRecentLoaderIds) {
- getLoaderManager().destroyLoader(interactionLoaderId);
- }
- }
-
private void runEntranceAnimation() {
if (mHasAlreadyBeenOpened) {
return;
@@ -1159,75 +1052,9 @@
}
private void bindDataToCards(Cp2DataCardModel cp2DataCardModel) {
- startInteractionLoaders(cp2DataCardModel);
populateContactAndAboutCard(cp2DataCardModel, /* shouldAddPhoneticName */ true);
}
- private void startInteractionLoaders(Cp2DataCardModel cp2DataCardModel) {
- final Map<String, List<DataItem>> dataItemsMap = cp2DataCardModel.dataItemsMap;
- final List<DataItem> phoneDataItems = dataItemsMap.get(Phone.CONTENT_ITEM_TYPE);
- final List<DataItem> sipCallDataItems = dataItemsMap.get(SipAddress.CONTENT_ITEM_TYPE);
- if (phoneDataItems != null && phoneDataItems.size() == 1) {
- mOnlyOnePhoneNumber = true;
- } else {
- mOnlyOnePhoneNumber = false;
- }
- String[] phoneNumbers = null;
- if (phoneDataItems != null) {
- phoneNumbers = new String[phoneDataItems.size()];
- for (int i = 0; i < phoneDataItems.size(); ++i) {
- phoneNumbers[i] = ((PhoneDataItem) phoneDataItems.get(i)).getNumber();
- }
- }
- String[] sipNumbers = null;
- if (sipCallDataItems != null) {
- sipNumbers = new String[sipCallDataItems.size()];
- for (int i = 0; i < sipCallDataItems.size(); ++i) {
- sipNumbers[i] = ((SipAddressDataItem) sipCallDataItems.get(i)).getSipAddress();
- }
- }
- final Bundle phonesExtraBundle = new Bundle();
- phonesExtraBundle.putStringArray(KEY_LOADER_EXTRA_PHONES, phoneNumbers);
- phonesExtraBundle.putStringArray(KEY_LOADER_EXTRA_SIP_NUMBERS, sipNumbers);
-
- Trace.beginSection("start sms loader");
- getLoaderManager().initLoader(
- LOADER_SMS_ID,
- phonesExtraBundle,
- mLoaderInteractionsCallbacks);
- Trace.endSection();
-
- Trace.beginSection("start call log loader");
- getLoaderManager().initLoader(
- LOADER_CALL_LOG_ID,
- phonesExtraBundle,
- mLoaderInteractionsCallbacks);
- Trace.endSection();
-
-
- Trace.beginSection("start calendar loader");
- final List<DataItem> emailDataItems = dataItemsMap.get(Email.CONTENT_ITEM_TYPE);
- if (emailDataItems != null && emailDataItems.size() == 1) {
- mOnlyOneEmail = true;
- } else {
- mOnlyOneEmail = false;
- }
- String[] emailAddresses = null;
- if (emailDataItems != null) {
- emailAddresses = new String[emailDataItems.size()];
- for (int i = 0; i < emailDataItems.size(); ++i) {
- emailAddresses[i] = ((EmailDataItem) emailDataItems.get(i)).getAddress();
- }
- }
- final Bundle emailsExtraBundle = new Bundle();
- emailsExtraBundle.putStringArray(KEY_LOADER_EXTRA_EMAILS, emailAddresses);
- getLoaderManager().initLoader(
- LOADER_CALENDAR_ID,
- emailsExtraBundle,
- mLoaderInteractionsCallbacks);
- Trace.endSection();
- }
-
private void showActivity() {
if (mScroller != null) {
mScroller.setVisibility(View.VISIBLE);
@@ -1268,13 +1095,6 @@
populateContactAndAboutCard(mCachedCp2DataCardModel, /* shouldAddPhoneticName */ false);
}
- // When exiting the activity and resuming, we want to force a full reload of all the
- // interaction data in case something changed in the background. On screen rotation,
- // we don't need to do this. And, mCachedCp2DataCardModel will be null, so we won't.
- if (mCachedCp2DataCardModel != null) {
- destroyInteractionLoaders();
- startInteractionLoaders(mCachedCp2DataCardModel);
- }
maybeShowProgressDialog();
}
@@ -1373,16 +1193,13 @@
mNoContactDetailsCard.setVisibility(View.GONE);
}
- // If the Recent card is already initialized (all recent data is loaded), show the About
- // card if it has entries. Otherwise About card visibility will be set in bindRecentData()
+ // Show the About card if it has entries
if (aboutCardEntries.size() > 0) {
if (mAboutCard.getVisibility() == View.GONE && mShouldLog) {
Logger.logQuickContactEvent(mReferrer, mContactType, CardType.ABOUT,
ActionType.UNKNOWN_ACTION, /* thirdPartyAction */ null);
}
- if (isAllRecentDataLoaded()) {
- mAboutCard.setVisibility(View.VISIBLE);
- }
+ mAboutCard.setVisibility(View.VISIBLE);
}
Trace.endSection();
}
@@ -2263,7 +2080,6 @@
mColorFilter =
new PorterDuffColorFilter(mColorFilterColor, PorterDuff.Mode.SRC_ATOP);
mContactCard.setColorAndFilter(mColorFilterColor, mColorFilter);
- mRecentCard.setColorAndFilter(mColorFilterColor, mColorFilter);
mAboutCard.setColorAndFilter(mColorFilterColor, mColorFilter);
}
@@ -2296,38 +2112,6 @@
return 0;
}
- private List<Entry> contactInteractionsToEntries(List<ContactInteraction> interactions) {
- final List<Entry> entries = new ArrayList<>();
- for (ContactInteraction interaction : interactions) {
- if (interaction == null) {
- continue;
- }
- entries.add(new Entry(/* id = */ -1,
- interaction.getIcon(this),
- interaction.getViewHeader(this),
- interaction.getViewBody(this),
- interaction.getBodyIcon(this),
- interaction.getViewFooter(this),
- interaction.getFooterIcon(this),
- interaction.getContentDescription(this),
- interaction.getIntent(),
- /* alternateIcon = */ null,
- /* alternateIntent = */ null,
- /* alternateContentDescription = */ null,
- /* shouldApplyColor = */ true,
- /* isEditable = */ false,
- /* EntryContextMenuInfo = */ null,
- /* thirdIcon = */ null,
- /* thirdIntent = */ null,
- /* thirdContentDescription = */ null,
- /* thirdAction = */ Entry.ACTION_NONE,
- /* thirdActionExtras = */ null,
- /* shouldApplyThirdIconColor = */ true,
- interaction.getIconResourceId()));
- }
- return entries;
- }
-
private final LoaderCallbacks<Contact> mLoaderContactCallbacks =
new LoaderCallbacks<Contact>() {
@Override
@@ -2411,201 +2195,6 @@
overridePendingTransition(0, 0);
}
- private final LoaderCallbacks<List<ContactInteraction>> mLoaderInteractionsCallbacks =
- new LoaderCallbacks<List<ContactInteraction>>() {
-
- @Override
- public Loader<List<ContactInteraction>> onCreateLoader(int id, Bundle args) {
- Loader<List<ContactInteraction>> loader = null;
- switch (id) {
- case LOADER_SMS_ID:
- loader = new SmsInteractionsLoader(
- QuickContactActivity.this,
- args.getStringArray(KEY_LOADER_EXTRA_PHONES),
- MAX_SMS_RETRIEVE);
- break;
- case LOADER_CALENDAR_ID:
- final String[] emailsArray = args.getStringArray(KEY_LOADER_EXTRA_EMAILS);
- List<String> emailsList = null;
- if (emailsArray != null) {
- emailsList = Arrays.asList(args.getStringArray(KEY_LOADER_EXTRA_EMAILS));
- }
- loader = new CalendarInteractionsLoader(
- QuickContactActivity.this,
- emailsList,
- MAX_FUTURE_CALENDAR_RETRIEVE,
- MAX_PAST_CALENDAR_RETRIEVE,
- FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR,
- PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR);
- break;
- case LOADER_CALL_LOG_ID:
- loader = new CallLogInteractionsLoader(
- QuickContactActivity.this,
- args.getStringArray(KEY_LOADER_EXTRA_PHONES),
- args.getStringArray(KEY_LOADER_EXTRA_SIP_NUMBERS),
- MAX_CALL_LOG_RETRIEVE);
- }
- return loader;
- }
-
- @Override
- public void onLoadFinished(Loader<List<ContactInteraction>> loader,
- List<ContactInteraction> data) {
- mRecentLoaderResults.put(loader.getId(), data);
-
- if (isAllRecentDataLoaded()) {
- bindRecentData();
- }
- }
-
- @Override
- public void onLoaderReset(Loader<List<ContactInteraction>> loader) {
- mRecentLoaderResults.remove(loader.getId());
- }
- };
-
- private boolean isAllRecentDataLoaded() {
- return mRecentLoaderResults.size() == mRecentLoaderIds.length;
- }
-
- private void bindRecentData() {
- final List<ContactInteraction> allInteractions = new ArrayList<>();
- final List<List<Entry>> interactionsWrapper = new ArrayList<>();
-
- // Serialize mRecentLoaderResults into a single list. This should be done on the main
- // thread to avoid races against mRecentLoaderResults edits.
- for (List<ContactInteraction> loaderInteractions : mRecentLoaderResults.values()) {
- allInteractions.addAll(loaderInteractions);
- }
-
- mRecentDataTask = new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- Trace.beginSection("sort recent loader results");
-
- // Sort the interactions by most recent
- Collections.sort(allInteractions, new Comparator<ContactInteraction>() {
- @Override
- public int compare(ContactInteraction a, ContactInteraction b) {
- if (a == null && b == null) {
- return 0;
- }
- if (a == null) {
- return 1;
- }
- if (b == null) {
- return -1;
- }
- if (a.getInteractionDate() > b.getInteractionDate()) {
- return -1;
- }
- if (a.getInteractionDate() == b.getInteractionDate()) {
- return 0;
- }
- return 1;
- }
- });
-
- Trace.endSection();
- Trace.beginSection("contactInteractionsToEntries");
-
- // Wrap each interaction in its own list so that an icon is displayed for each entry
- for (Entry contactInteraction : contactInteractionsToEntries(allInteractions)) {
- List<Entry> entryListWrapper = new ArrayList<>(1);
- entryListWrapper.add(contactInteraction);
- interactionsWrapper.add(entryListWrapper);
- }
-
- Trace.endSection();
- return null;
- }
-
- @Override
- protected void onPostExecute(Void aVoid) {
- super.onPostExecute(aVoid);
- Trace.beginSection("initialize recents card");
-
- if (allInteractions.size() > 0) {
- mRecentCard.initialize(interactionsWrapper,
- /* numInitialVisibleEntries = */ MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN,
- /* isExpanded = */ mRecentCard.isExpanded(), /* isAlwaysExpanded = */ false,
- mExpandingEntryCardViewListener, mScroller);
- if (mRecentCard.getVisibility() == View.GONE && mShouldLog) {
- Logger.logQuickContactEvent(mReferrer, mContactType, CardType.RECENT,
- ActionType.UNKNOWN_ACTION, /* thirdPartyAction */ null);
- }
- mRecentCard.setVisibility(View.VISIBLE);
- } else {
- mRecentCard.setVisibility(View.GONE);
- }
-
- Trace.endSection();
- Trace.beginSection("initialize permission explanation card");
-
- final Drawable historyIcon = ResourcesCompat.getDrawable(getResources(),
- R.drawable.quantum_ic_history_vd_theme_24, null);
-
- final Entry permissionExplanationEntry = new Entry(CARD_ENTRY_ID_REQUEST_PERMISSION,
- historyIcon, getString(R.string.permission_explanation_header),
- mPermissionExplanationCardSubHeader, /* subHeaderIcon = */ null,
- /* text = */ null, /* textIcon = */ null,
- /* primaryContentDescription = */ null, getIntent(),
- /* alternateIcon = */ null, /* alternateIntent = */ null,
- /* alternateContentDescription = */ null, /* shouldApplyColor = */ true,
- /* isEditable = */ false, /* EntryContextMenuInfo = */ null,
- /* thirdIcon = */ null, /* thirdIntent = */ null,
- /* thirdContentDescription = */ null, /* thirdAction = */ Entry.ACTION_NONE,
- /* thirdExtras = */ null,
- /* shouldApplyThirdIconColor = */ true,
- R.drawable.quantum_ic_history_vd_theme_24);
-
- final List<List<Entry>> permissionExplanationEntries = new ArrayList<>();
- permissionExplanationEntries.add(new ArrayList<Entry>());
- permissionExplanationEntries.get(0).add(permissionExplanationEntry);
-
- final int subHeaderTextColor = getResources().getColor(android.R.color.white);
- final PorterDuffColorFilter whiteColorFilter =
- new PorterDuffColorFilter(subHeaderTextColor, PorterDuff.Mode.SRC_ATOP);
-
- mPermissionExplanationCard.initialize(permissionExplanationEntries,
- /* numInitialVisibleEntries = */ 1,
- /* isExpanded = */ true,
- /* isAlwaysExpanded = */ true,
- /* listener = */ null,
- mScroller);
-
- mPermissionExplanationCard.setColorAndFilter(subHeaderTextColor, whiteColorFilter);
- mPermissionExplanationCard.setBackgroundColor(mColorFilterColor);
- mPermissionExplanationCard.setEntryHeaderColor(subHeaderTextColor);
- mPermissionExplanationCard.setEntrySubHeaderColor(subHeaderTextColor);
-
- if (mShouldShowPermissionExplanation) {
- if (mPermissionExplanationCard.getVisibility() == View.GONE
- && mShouldLog) {
- Logger.logQuickContactEvent(mReferrer, mContactType, CardType.PERMISSION,
- ActionType.UNKNOWN_ACTION, /* thirdPartyAction */ null);
- }
- mPermissionExplanationCard.setVisibility(View.VISIBLE);
- } else {
- mPermissionExplanationCard.setVisibility(View.GONE);
- }
-
- Trace.endSection();
-
- // About card is initialized along with the contact card, but since it appears after
- // the recent card in the UI, we hold off until making it visible until the recent
- // card is also ready to avoid stuttering.
- if (mAboutCard.shouldShow()) {
- mAboutCard.setVisibility(View.VISIBLE);
- } else {
- mAboutCard.setVisibility(View.GONE);
- }
- mRecentDataTask = null;
- }
- };
- mRecentDataTask.execute();
- }
-
@Override
protected void onStop() {
super.onStop();
@@ -2617,9 +2206,6 @@
// the entire process will be killed.
mEntriesAndActionsTask.cancel(/* mayInterruptIfRunning = */ false);
}
- if (mRecentDataTask != null) {
- mRecentDataTask.cancel(/* mayInterruptIfRunning = */ false);
- }
}
@Override
diff --git a/src/com/android/contacts/util/ContactDisplayUtils.java b/src/com/android/contacts/util/ContactDisplayUtils.java
index b69a088..ff2d202 100644
--- a/src/com/android/contacts/util/ContactDisplayUtils.java
+++ b/src/com/android/contacts/util/ContactDisplayUtils.java
@@ -18,22 +18,17 @@
import static android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.content.Context;
import android.content.res.Resources;
-import androidx.annotation.Nullable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.TtsSpan;
-import android.util.Log;
import android.util.Patterns;
-
+import androidx.annotation.Nullable;
import com.android.contacts.R;
import com.android.contacts.compat.PhoneNumberUtilsCompat;
import com.android.contacts.preference.ContactsPreferences;
-import com.google.common.base.Preconditions;
-
/**
* Methods for handling various contact data labels.
*/
@@ -41,9 +36,6 @@
private static final String TAG = ContactDisplayUtils.class.getSimpleName();
- public static final int INTERACTION_CALL = 1;
- public static final int INTERACTION_SMS = 2;
-
/**
* Checks if the given data type is a custom type.
*
@@ -55,39 +47,6 @@
}
/**
- * Gets a display label for a given phone type.
- *
- * @param type The type of number.
- * @param customLabel A custom label to use if the phone is determined to be of custom type
- * determined by {@link #isCustomPhoneType(Integer))}
- * @param interactionType whether this is a call or sms. Either {@link #INTERACTION_CALL} or
- * {@link #INTERACTION_SMS}.
- * @param context The application context.
- * @return An appropriate string label
- */
- public static CharSequence getLabelForCallOrSms(Integer type, CharSequence customLabel,
- int interactionType, Context context) {
- Preconditions.checkNotNull(context);
-
- if (isCustomPhoneType(type)) {
- return (customLabel == null) ? "" : customLabel;
- } else {
- int resId;
- if (interactionType == INTERACTION_SMS) {
- resId = getSmsLabelResourceId(type);
- } else {
- resId = getPhoneLabelResourceId(type);
- if (interactionType != INTERACTION_CALL) {
- Log.e(TAG, "Un-recognized interaction type: " + interactionType +
- ". Defaulting to ContactDisplayUtils.INTERACTION_CALL.");
- }
- }
-
- return context.getResources().getText(resId);
- }
- }
-
- /**
* Find a label for calling.
*
* @param type The type of number.
diff --git a/tests/src/com/android/contacts/NoPermissionsLaunchSmokeTest.java b/tests/src/com/android/contacts/NoPermissionsLaunchSmokeTest.java
index b8eccd7..fac9c85 100644
--- a/tests/src/com/android/contacts/NoPermissionsLaunchSmokeTest.java
+++ b/tests/src/com/android/contacts/NoPermissionsLaunchSmokeTest.java
@@ -32,7 +32,6 @@
* $ adb shell pm revoke com.android.contacts android.permission.WRITE_CONTACTS
* $ adb shell pm revoke com.android.contacts android.permission.GET_ACCOUNTS
* $ adb shell pm revoke com.android.contacts android.permission.READ_PHONE_STATE
- * $ adb shell pm revoke com.android.contacts android.permission.READ_CALL_LOG
* $ adb shell pm revoke com.android.contacts android.permission.CALL_PHONE
* $ adb shell am instrument -w \
* com.google.android.contacts.tests/androidx.test.runner.AndroidJUnitRunner \
@@ -54,7 +53,6 @@
assumeTrue(!hasPermission(mTargetContext, Manifest.permission.WRITE_CONTACTS));
assumeTrue(!hasPermission(mTargetContext, Manifest.permission.GET_ACCOUNTS));
assumeTrue(!hasPermission(mTargetContext, Manifest.permission.READ_PHONE_STATE));
- assumeTrue(!hasPermission(mTargetContext, Manifest.permission.READ_CALL_LOG));
assumeTrue(!hasPermission(mTargetContext, Manifest.permission.CALL_PHONE));
// remove state that might exist outside of the app
diff --git a/tests/src/com/android/contacts/interactions/CallLogInteractionsLoaderTest.java b/tests/src/com/android/contacts/interactions/CallLogInteractionsLoaderTest.java
deleted file mode 100644
index b51affd..0000000
--- a/tests/src/com/android/contacts/interactions/CallLogInteractionsLoaderTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.android.contacts.interactions;
-
-import android.content.ContentValues;
-import android.provider.CallLog.Calls;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests {@link CallLogInteractionsLoader}
- */
-@SmallTest
-public class CallLogInteractionsLoaderTest extends AndroidTestCase {
-
- public void testCallLogInteractions_pruneDuplicates_containsDuplicates() {
- List<ContactInteraction> interactions = new ArrayList<>();
- int maxToRetrieve = 5;
-
- ContentValues interactionOneValues = new ContentValues();
- interactionOneValues.put(Calls.DATE, 1L);
- interactions.add(new CallLogInteraction(interactionOneValues));
-
- ContentValues interactionTwoValues = new ContentValues();
- interactionTwoValues.put(Calls.DATE, 1L);
- interactions.add(new CallLogInteraction(interactionTwoValues));
-
- interactions = CallLogInteractionsLoader.pruneDuplicateCallLogInteractions(interactions,
- maxToRetrieve);
- assertEquals(1, interactions.size());
- }
-
- public void testCallLogInteractions_pruneDuplicates_containsNoDuplicates() {
- List<ContactInteraction> interactions = new ArrayList<>();
- int maxToRetrieve = 5;
-
- ContentValues interactionOneValues = new ContentValues();
- interactionOneValues.put(Calls.DATE, 1L);
- interactions.add(new CallLogInteraction(interactionOneValues));
-
- ContentValues interactionTwoValues = new ContentValues();
- interactionTwoValues.put(Calls.DATE, 5L);
- interactions.add(new CallLogInteraction(interactionTwoValues));
-
- interactions = CallLogInteractionsLoader.pruneDuplicateCallLogInteractions(interactions,
- maxToRetrieve);
- assertEquals(2, interactions.size());
- }
-
- public void testCallLogInteractions_maxToRetrieve() {
- List<ContactInteraction> interactions = new ArrayList<>();
- int maxToRetrieve = 1;
-
- ContentValues interactionOneValues = new ContentValues();
- interactionOneValues.put(Calls.DATE, 1L);
- interactions.add(new CallLogInteraction(interactionOneValues));
-
- ContentValues interactionTwoValues = new ContentValues();
- interactionTwoValues.put(Calls.DATE, 5L);
- interactions.add(new CallLogInteraction(interactionTwoValues));
-
- interactions = CallLogInteractionsLoader.pruneDuplicateCallLogInteractions(interactions,
- maxToRetrieve);
- assertEquals(1, interactions.size());
- }
-}
diff --git a/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java b/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
index 5f95a1b..654533b 100644
--- a/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
@@ -15,11 +15,8 @@
*/
package com.android.contacts.interactions;
-import android.content.res.Configuration;
-import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-
import java.util.Calendar;
import java.util.Locale;
@@ -28,26 +25,6 @@
*/
@SmallTest
public class ContactInteractionUtilTest extends AndroidTestCase {
-
- private Locale mOriginalLocale;
- private Calendar calendar;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- calendar = Calendar.getInstance();
-
- // Time/Date utilities rely on specific locales. Forace US and set back in tearDown()
- mOriginalLocale = Locale.getDefault();
- setLocale(Locale.US);
- }
-
- @Override
- protected void tearDown() throws Exception {
- setLocale(mOriginalLocale);
- super.tearDown();
- }
-
public void testOneQuestionMark() {
assertEquals("(?)", ContactInteractionUtil.questionMarks(1));
}
@@ -59,69 +36,4 @@
public void testFiveQuestionMarks() {
assertEquals("(?,?,?,?,?)", ContactInteractionUtil.questionMarks(5));
}
-
- public void testFormatDateStringFromTimestamp_todaySingleMinuteAm() {
- // Test today scenario (time shown)
- // Single digit minute & AM
- calendar.set(Calendar.HOUR_OF_DAY, 8);
- calendar.set(Calendar.MINUTE, 8);
- long todayTimestamp = calendar.getTimeInMillis();
- assertEquals("8:08 AM", ContactInteractionUtil.formatDateStringFromTimestamp(
- calendar.getTimeInMillis(), getContext()));
- }
-
- public void testFormatDateStringFromTimestamp_todayDoubleMinutePm() {
- // Double digit minute & PM
- calendar.set(Calendar.HOUR_OF_DAY, 22);
- calendar.set(Calendar.MINUTE, 18);
- assertEquals("10:18 PM",
- ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
- getContext()));
- }
-
- public void testFormatDateStringFromTimestamp_other() {
- // Test other (Month Date)
- calendar.set(
- /* year = */ 1991,
- /* month = */ Calendar.MONTH,
- /* day = */ 11,
- /* hourOfDay = */ 8,
- /* minute = */ 8);
- assertEquals("Monday, March 11, 1991, 8:08 AM",
- ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
- getContext()));
- }
-
- public void testFormatDuration_zero() {
- assertEquals("0 sec",
- ContactInteractionUtil.formatDuration(0, getContext()));
- }
-
- public void testFormatDuration_minZeroSec() {
- assertEquals("1 min 0 sec",
- ContactInteractionUtil.formatDuration(60, getContext()));
- }
-
- public void testFormatDuration_minSec() {
- assertEquals("30 min 9 sec",
- ContactInteractionUtil.formatDuration(1809, getContext()));
- }
-
- public void testFormatDuration_hrZeroMinZeroSec() {
- assertEquals("1 hr 0 min 0 sec",
- ContactInteractionUtil.formatDuration(3600, getContext()));
- }
-
- public void testFormatDuration_hrMinSec() {
- assertEquals("2 hr 44 min 36 sec",
- ContactInteractionUtil.formatDuration(9876, getContext()));
- }
-
- private void setLocale(Locale locale) {
- Locale.setDefault(locale);
- Resources res = getContext().getResources();
- Configuration config = res.getConfiguration();
- config.locale = locale;
- res.updateConfiguration(config, res.getDisplayMetrics());
- }
}
\ No newline at end of file
diff --git a/tests/src/com/android/contacts/interactions/TestLoaderManager.java b/tests/src/com/android/contacts/interactions/TestLoaderManager.java
index dacf616..7a3dbe3 100644
--- a/tests/src/com/android/contacts/interactions/TestLoaderManager.java
+++ b/tests/src/com/android/contacts/interactions/TestLoaderManager.java
@@ -111,7 +111,7 @@
@Override
public void run() {
try {
- AsyncTaskLoader.class.getMethod("waitForLoader").invoke(loader, null);
+ AsyncTaskLoader.class.getMethod("waitForLoader").invoke(loader);
} catch (Throwable e) {
Log.e(TAG, "Exception while waiting for loader: " + loader.getId(), e);
Assert.fail("Exception while waiting for loader: " + loader.getId());
diff --git a/tests/src/com/android/contacts/util/ContactDisplayUtilTests.java b/tests/src/com/android/contacts/util/ContactDisplayUtilTests.java
index 88c9e29..1503215 100644
--- a/tests/src/com/android/contacts/util/ContactDisplayUtilTests.java
+++ b/tests/src/com/android/contacts/util/ContactDisplayUtilTests.java
@@ -57,40 +57,6 @@
assertFalse(ContactDisplayUtils.isCustomPhoneType(Phone.TYPE_OTHER));
}
- public void testGetLabelForCallOrSmsReturnsCustomLabel() {
- final CharSequence smsResult = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_CUSTOM,
- "expected sms label", ContactDisplayUtils.INTERACTION_SMS, getContext());
- assertEquals("expected sms label", smsResult);
-
- final CharSequence callResult = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_CUSTOM,
- "expected call label", ContactDisplayUtils.INTERACTION_CALL, getContext());
- assertEquals("expected call label", callResult);
- }
-
- public void testGetLabelForCallOrSmsReturnsCallLabels() {
- CharSequence result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_HOME, "",
- ContactDisplayUtils.INTERACTION_CALL, getContext());
- CharSequence expected = getContext().getResources().getText(R.string.call_home);
- assertEquals(expected, result);
-
- result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_MOBILE, "",
- ContactDisplayUtils.INTERACTION_CALL, getContext());
- expected = getContext().getResources().getText(R.string.call_mobile);
- assertEquals(expected, result);
- }
-
- public void testGetLabelForCallOrSmsReturnsSmsLabels() {
- CharSequence result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_HOME, "",
- ContactDisplayUtils.INTERACTION_SMS, getContext());
- CharSequence expected = getContext().getResources().getText(R.string.sms_home);
- assertEquals(expected, result);
-
- result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_MOBILE, "",
- ContactDisplayUtils.INTERACTION_SMS, getContext());
- expected = getContext().getResources().getText(R.string.sms_mobile);
- assertEquals(expected, result);
- }
-
public void testGetPhoneLabelResourceIdReturnsOther() {
assertEquals(R.string.call_other, ContactDisplayUtils.getPhoneLabelResourceId(null));
}