summaryrefslogtreecommitdiff
path: root/java/com
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2018-01-23 23:32:39 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-01-23 23:32:39 +0000
commit813fa56b9a21551feb506dd5d695fee5e513ad94 (patch)
tree180d720c77e5148593d9d6ecc34af94ba0d46b05 /java/com
parent602563008ae1c0acc873fd183ce298e199949677 (diff)
parentb52ea741beaf9d852c3dc6797fac52a3351e0dd9 (diff)
Merge changes I989422c4,Ibdefc49c,I463c8ed4,I813e9d69,Ie6539ce2
* changes: Bubble bottom action changes. Contacts recyclerview is now hidden when we don't have contacts permission. Moved coalesced_ids.proto and number_attributes.proto to calllog/database/contract. Write PhoneLookup results to PhoneLookupHistory in RealtimeRowProcessor. Attempt to work around sqlite database cursor window issue
Diffstat (limited to 'java/com')
-rw-r--r--java/com/android/dialer/calllog/database/contract/coalesced_ids.proto (renamed from java/com/android/dialer/calllog/model/coalesced_ids.proto)0
-rw-r--r--java/com/android/dialer/calllog/database/contract/number_attributes.proto (renamed from java/com/android/dialer/calllog/model/number_attributes.proto)0
-rw-r--r--java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java103
-rw-r--r--java/com/android/dialer/contactsfragment/ContactsFragment.java15
-rw-r--r--java/com/android/dialer/database/DialerDatabaseHelper.java37
-rw-r--r--java/com/android/newbubble/BottomActionViewController.java4
-rw-r--r--java/com/android/newbubble/NewMoveHandler.java8
7 files changed, 150 insertions, 17 deletions
diff --git a/java/com/android/dialer/calllog/model/coalesced_ids.proto b/java/com/android/dialer/calllog/database/contract/coalesced_ids.proto
index 059f95782..059f95782 100644
--- a/java/com/android/dialer/calllog/model/coalesced_ids.proto
+++ b/java/com/android/dialer/calllog/database/contract/coalesced_ids.proto
diff --git a/java/com/android/dialer/calllog/model/number_attributes.proto b/java/com/android/dialer/calllog/database/contract/number_attributes.proto
index 64f8f180e..64f8f180e 100644
--- a/java/com/android/dialer/calllog/model/number_attributes.proto
+++ b/java/com/android/dialer/calllog/database/contract/number_attributes.proto
diff --git a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
index 9e58e53ad..86cc24c04 100644
--- a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
+++ b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java
@@ -16,22 +16,37 @@
package com.android.dialer.calllog.ui;
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
import android.content.Context;
import android.support.annotation.MainThread;
+import android.support.annotation.VisibleForTesting;
import android.util.ArrayMap;
import com.android.dialer.DialerPhoneNumber;
import com.android.dialer.NumberAttributes;
import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
import com.android.dialer.common.concurrent.Annotations.Ui;
+import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.inject.ApplicationContext;
import com.android.dialer.phonelookup.PhoneLookup;
import com.android.dialer.phonelookup.PhoneLookupInfo;
import com.android.dialer.phonelookup.consolidator.PhoneLookupInfoConsolidator;
+import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract;
+import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
+import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import java.util.ArrayList;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
/**
@@ -44,22 +59,36 @@ import javax.inject.Inject;
* <p>For example, when there are many invalid numbers in the call log, we cannot efficiently update
* the CP2 information for all of them at once, and so information for those rows must be retrieved
* at display time.
+ *
+ * <p>This class also updates {@link PhoneLookupHistory} with the results that it fetches.
*/
public final class RealtimeRowProcessor {
+ /*
+ * The time to wait between writing batches of records to PhoneLookupHistory.
+ */
+ @VisibleForTesting static final long BATCH_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3);
+
private final Context appContext;
private final PhoneLookup<PhoneLookupInfo> phoneLookup;
private final ListeningExecutorService uiExecutor;
+ private final ListeningExecutorService backgroundExecutor;
private final Map<DialerPhoneNumber, PhoneLookupInfo> cache = new ArrayMap<>();
+ private final Map<DialerPhoneNumber, PhoneLookupInfo> queuedPhoneLookupHistoryWrites =
+ new ArrayMap<>();
+ private final Runnable writePhoneLookupHistoryRunnable = this::writePhoneLookupHistory;
+
@Inject
RealtimeRowProcessor(
@ApplicationContext Context appContext,
@Ui ListeningExecutorService uiExecutor,
+ @BackgroundExecutor ListeningExecutorService backgroundExecutor,
PhoneLookup<PhoneLookupInfo> phoneLookup) {
this.appContext = appContext;
this.uiExecutor = uiExecutor;
+ this.backgroundExecutor = backgroundExecutor;
this.phoneLookup = phoneLookup;
}
@@ -83,6 +112,7 @@ public final class RealtimeRowProcessor {
return Futures.transform(
phoneLookupInfoFuture,
phoneLookupInfo -> {
+ queuePhoneLookupHistoryWrite(row.number(), phoneLookupInfo);
cache.put(row.number(), phoneLookupInfo);
return applyPhoneLookupInfoToRow(phoneLookupInfo, row);
},
@@ -96,6 +126,79 @@ public final class RealtimeRowProcessor {
cache.clear();
}
+ @MainThread
+ private void queuePhoneLookupHistoryWrite(
+ DialerPhoneNumber dialerPhoneNumber, PhoneLookupInfo phoneLookupInfo) {
+ Assert.isMainThread();
+ queuedPhoneLookupHistoryWrites.put(dialerPhoneNumber, phoneLookupInfo);
+ ThreadUtil.getUiThreadHandler().removeCallbacks(writePhoneLookupHistoryRunnable);
+ ThreadUtil.getUiThreadHandler().postDelayed(writePhoneLookupHistoryRunnable, BATCH_WAIT_MILLIS);
+ }
+
+ @MainThread
+ private void writePhoneLookupHistory() {
+ Assert.isMainThread();
+
+ // Copy the batch to a new collection that be safely processed on a background thread.
+ ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> currentBatch =
+ ImmutableMap.copyOf(queuedPhoneLookupHistoryWrites);
+
+ // Clear the queue, handing responsibility for its items to the background task.
+ queuedPhoneLookupHistoryWrites.clear();
+
+ // Returns the number of rows updated.
+ ListenableFuture<Integer> applyBatchFuture =
+ backgroundExecutor.submit(
+ () -> {
+ DialerPhoneNumberUtil dialerPhoneNumberUtil =
+ new DialerPhoneNumberUtil(PhoneNumberUtil.getInstance());
+
+ ArrayList<ContentProviderOperation> operations = new ArrayList<>();
+ long currentTimestamp = System.currentTimeMillis();
+ for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry : currentBatch.entrySet()) {
+ DialerPhoneNumber dialerPhoneNumber = entry.getKey();
+ PhoneLookupInfo phoneLookupInfo = entry.getValue();
+
+ // Note: Multiple DialerPhoneNumbers can map to the same normalized number but we
+ // just write them all and the value for the last one will arbitrarily win.
+ String normalizedNumber = dialerPhoneNumberUtil.normalizeNumber(dialerPhoneNumber);
+
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(
+ PhoneLookupHistory.PHONE_LOOKUP_INFO, phoneLookupInfo.toByteArray());
+ contentValues.put(PhoneLookupHistory.LAST_MODIFIED, currentTimestamp);
+ operations.add(
+ ContentProviderOperation.newUpdate(
+ PhoneLookupHistory.contentUriForNumber(normalizedNumber))
+ .withValues(contentValues)
+ .build());
+ }
+ return Assert.isNotNull(
+ appContext
+ .getContentResolver()
+ .applyBatch(PhoneLookupHistoryContract.AUTHORITY, operations))
+ .length;
+ });
+
+ Futures.addCallback(
+ applyBatchFuture,
+ new FutureCallback<Integer>() {
+ @Override
+ public void onSuccess(Integer rowsAffected) {
+ LogUtil.i(
+ "RealtimeRowProcessor.onSuccess",
+ "wrote %d rows to PhoneLookupHistory",
+ rowsAffected);
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ throw new RuntimeException(throwable);
+ }
+ },
+ uiExecutor);
+ }
+
private CoalescedRow applyPhoneLookupInfoToRow(
PhoneLookupInfo phoneLookupInfo, CoalescedRow row) {
PhoneLookupInfoConsolidator phoneLookupInfoConsolidator =
diff --git a/java/com/android/dialer/contactsfragment/ContactsFragment.java b/java/com/android/dialer/contactsfragment/ContactsFragment.java
index 714739300..ae2bd746a 100644
--- a/java/com/android/dialer/contactsfragment/ContactsFragment.java
+++ b/java/com/android/dialer/contactsfragment/ContactsFragment.java
@@ -46,7 +46,6 @@ import com.android.contacts.common.preference.ContactsPreferences.ChangeListener
import com.android.dialer.common.Assert;
import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
-import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener;
import com.android.dialer.performancereport.PerformanceReport;
import com.android.dialer.util.DialerUtils;
import com.android.dialer.util.IntentUtil;
@@ -86,7 +85,7 @@ public class ContactsFragment extends Fragment
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- getLoaderManager().initLoader(0, null, ContactsFragment.this);
+ loadContacts();
}
};
@@ -208,11 +207,12 @@ public class ContactsFragment extends Fragment
emptyContentView.setActionClickedListener(this);
if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
- getLoaderManager().initLoader(0, null, this);
+ loadContacts();
} else {
emptyContentView.setDescription(R.string.permission_no_contacts);
emptyContentView.setActionLabel(R.string.permission_single_turn_on);
emptyContentView.setVisibility(View.VISIBLE);
+ recyclerView.setVisibility(View.GONE);
}
return view;
@@ -349,12 +349,17 @@ public class ContactsFragment extends Fragment
if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) {
if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
// Force a refresh of the data since we were missing the permission before this.
- emptyContentView.setVisibility(View.GONE);
- getLoaderManager().initLoader(0, null, this);
+ PermissionsUtil.notifyPermissionGranted(getContext(), permissions[0]);
}
}
}
+ private void loadContacts() {
+ getLoaderManager().initLoader(0, null, this);
+ recyclerView.setVisibility(View.VISIBLE);
+ emptyContentView.setVisibility(View.GONE);
+ }
+
/** Listener for contacts list scroll state. */
public interface OnContactsListScrolledListener {
void onContactsListScrolled(boolean isDragging);
diff --git a/java/com/android/dialer/database/DialerDatabaseHelper.java b/java/com/android/dialer/database/DialerDatabaseHelper.java
index bc70fa46f..18c61342d 100644
--- a/java/com/android/dialer/database/DialerDatabaseHelper.java
+++ b/java/com/android/dialer/database/DialerDatabaseHelper.java
@@ -41,6 +41,7 @@ import com.android.contacts.common.util.StopWatch;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.common.database.Selection;
import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
import com.android.dialer.smartdial.util.SmartDialNameMatcher;
import com.android.dialer.smartdial.util.SmartDialPrefix;
@@ -351,24 +352,40 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper {
* other apps since last update.
*
* @param db Database to operate on.
- * @param deletedContactCursor Cursor containing rows of deleted contacts
+ * @param lastUpdatedTimeMillis the last time at which an update to the smart dial database was
+ * run.
*/
- @VisibleForTesting
- void removeDeletedContacts(SQLiteDatabase db, Cursor deletedContactCursor) {
+ private void removeDeletedContacts(SQLiteDatabase db, String lastUpdatedTimeMillis) {
+ Cursor deletedContactCursor = getDeletedContactCursor(lastUpdatedTimeMillis);
+
if (deletedContactCursor == null) {
return;
}
db.beginTransaction();
try {
- while (deletedContactCursor.moveToNext()) {
- final Long deleteContactId =
- deletedContactCursor.getLong(DeleteContactQuery.DELETED_CONTACT_ID);
- db.delete(
- Tables.SMARTDIAL_TABLE, SmartDialDbColumns.CONTACT_ID + "=" + deleteContactId, null);
- db.delete(Tables.PREFIX_TABLE, PrefixColumns.CONTACT_ID + "=" + deleteContactId, null);
+ if (!deletedContactCursor.moveToFirst()) {
+ return;
}
+ do {
+ Long deleteContactId = deletedContactCursor.getLong(DeleteContactQuery.DELETED_CONTACT_ID);
+
+ Selection smartDialSelection =
+ Selection.column(SmartDialDbColumns.CONTACT_ID).is("=", deleteContactId);
+ db.delete(
+ Tables.SMARTDIAL_TABLE,
+ smartDialSelection.getSelection(),
+ smartDialSelection.getSelectionArgs());
+
+ Selection prefixSelection =
+ Selection.column(PrefixColumns.CONTACT_ID).is("=", deleteContactId);
+ db.delete(
+ Tables.PREFIX_TABLE,
+ prefixSelection.getSelection(),
+ prefixSelection.getSelectionArgs());
+ } while (deletedContactCursor.moveToNext());
+
db.setTransactionSuccessful();
} finally {
deletedContactCursor.close();
@@ -633,7 +650,7 @@ public class DialerDatabaseHelper extends SQLiteOpenHelper {
}
/** Removes contacts that have been deleted. */
- removeDeletedContacts(db, getDeletedContactCursor(lastUpdateMillis));
+ removeDeletedContacts(db, lastUpdateMillis);
removePotentiallyCorruptedContacts(db, lastUpdateMillis);
if (DEBUG) {
diff --git a/java/com/android/newbubble/BottomActionViewController.java b/java/com/android/newbubble/BottomActionViewController.java
index 485d04169..04e0e5fe7 100644
--- a/java/com/android/newbubble/BottomActionViewController.java
+++ b/java/com/android/newbubble/BottomActionViewController.java
@@ -40,8 +40,8 @@ final class BottomActionViewController {
private final Context context;
private final WindowManager windowManager;
private final int gradientHeight;
- private final int bottomActionViewTop;
private final int textOffsetSize;
+ private int bottomActionViewTop;
private View bottomActionView;
private View dismissView;
@@ -55,7 +55,6 @@ final class BottomActionViewController {
windowManager = context.getSystemService(WindowManager.class);
gradientHeight =
context.getResources().getDimensionPixelSize(R.dimen.bubble_bottom_action_view_height);
- bottomActionViewTop = context.getResources().getDisplayMetrics().heightPixels - gradientHeight;
textOffsetSize =
context.getResources().getDimensionPixelSize(R.dimen.bubble_bottom_action_text_offset);
}
@@ -76,6 +75,7 @@ final class BottomActionViewController {
// Add the target to the window
// TODO(yueg): use TYPE_NAVIGATION_BAR_PANEL to draw over navigation bar
+ bottomActionViewTop = context.getResources().getDisplayMetrics().heightPixels - gradientHeight;
LayoutParams layoutParams =
new LayoutParams(
LayoutParams.MATCH_PARENT,
diff --git a/java/com/android/newbubble/NewMoveHandler.java b/java/com/android/newbubble/NewMoveHandler.java
index c00c10729..12e099c3a 100644
--- a/java/com/android/newbubble/NewMoveHandler.java
+++ b/java/com/android/newbubble/NewMoveHandler.java
@@ -251,6 +251,14 @@ class NewMoveHandler implements OnTouchListener {
}
}
break;
+ case MotionEvent.ACTION_CANCEL:
+ if (isMoving) {
+ snapX();
+ isMoving = false;
+ bubble.onMoveFinish();
+ bottomActionViewController.destroyBottomActionView();
+ }
+ break;
default: // fall out
}
return true;