Report usage of dynamic shortcuts.

Test
Manual:
* verify that app doesn't crash when quick contacts activity is opened on
  pre-N_MR1 device
* verify that usage is reported on N_MR1 with debugger
* Verify that shortcuts still update when a contact is favorited.

Bug 30189449

Change-Id: If2f959857dbb232482047637f8da94b610964c87
diff --git a/src/com/android/contacts/DynamicShortcuts.java b/src/com/android/contacts/DynamicShortcuts.java
index f02306c..c21f3a0 100644
--- a/src/com/android/contacts/DynamicShortcuts.java
+++ b/src/com/android/contacts/DynamicShortcuts.java
@@ -45,6 +45,7 @@
 
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.Experiments;
+import com.android.contacts.common.compat.CompatUtils;
 import com.android.contacts.common.util.BitmapUtil;
 import com.android.contacts.common.util.ImplicitIntentsUtil;
 import com.android.contactsbind.experiments.Flags;
@@ -68,6 +69,11 @@
 public class DynamicShortcuts {
     private static final String TAG = "DynamicShortcuts";
 
+    // Must be the same as shortcutId in res/xml/shortcuts.xml
+    // Note: This doesn't fit very well because this is a "static" shortcut but it's still the most
+    // sensible place to put it right now.
+    public static final String SHORTCUT_ADD_CONTACT = "shortcut-add-contact";
+
     // Note the Nexus launcher automatically truncates shortcut labels if they exceed these limits
     // however, we implement our own truncation in case the shortcut is shown on a launcher that
     // has different behavior
@@ -372,7 +378,10 @@
                 .addTriggerContentUri(new JobInfo.TriggerContentUri(ContactsContract.AUTHORITY_URI,
                         JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))
                 .setTriggerContentUpdateDelay(mContentChangeMinUpdateDelay)
-                .setTriggerContentMaxDelay(mContentChangeMaxUpdateDelay).build();
+                .setTriggerContentMaxDelay(mContentChangeMaxUpdateDelay)
+                // Minimize impact on UX by waiting for idle before updating.
+                .setRequiresDeviceIdle(true)
+                .build();
         mJobScheduler.schedule(job);
     }
 
@@ -390,7 +399,7 @@
                     flags.getInteger(Experiments.DYNAMIC_MAX_CONTENT_CHANGE_UPDATE_DELAY_MILLIS));
         }
 
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return;
+        if (!CompatUtils.isLauncherShortcutCompatible()) return;
 
         final DynamicShortcuts shortcuts = new DynamicShortcuts(context);
         if (!Flags.getInstance(context).getBoolean(Experiments.DYNAMIC_SHORTCUTS)) {
@@ -426,6 +435,13 @@
         return scheduler.getPendingJob(ContactsJobService.DYNAMIC_SHORTCUTS_JOB_ID) != null;
     }
 
+    public static void reportShortcutUsed(Context context, String lookupKey) {
+        if (!CompatUtils.isLauncherShortcutCompatible()) return;
+        final ShortcutManager shortcutManager = (ShortcutManager) context
+                .getSystemService(Context.SHORTCUT_SERVICE);
+        shortcutManager.reportShortcutUsed(lookupKey);
+    }
+
     private static class ShortcutUpdateTask extends AsyncTask<Void, Void, Void> {
         private DynamicShortcuts mDynamicShortcuts;
 
diff --git a/src/com/android/contacts/activities/CompactContactEditorActivity.java b/src/com/android/contacts/activities/CompactContactEditorActivity.java
index dc16049..fa2cb23 100644
--- a/src/com/android/contacts/activities/CompactContactEditorActivity.java
+++ b/src/com/android/contacts/activities/CompactContactEditorActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.activities;
 
+import com.android.contacts.DynamicShortcuts;
 import com.android.contacts.R;
 import com.android.contacts.common.activity.RequestPermissionsActivity;
 import com.android.contacts.common.model.RawContactDeltaList;
@@ -174,6 +175,10 @@
         final String action = getIntent().getAction();
         final Uri uri = Intent.ACTION_EDIT.equals(action) ? getIntent().getData() : null;
         mFragment.load(action, uri, getIntent().getExtras());
+
+        if (Intent.ACTION_INSERT.equals(action)) {
+            DynamicShortcuts.reportShortcutUsed(this, DynamicShortcuts.SHORTCUT_ADD_CONTACT);
+        }
     }
 
     protected void onSaveInstanceState(Bundle outState) {
diff --git a/src/com/android/contacts/common/compat/CompatUtils.java b/src/com/android/contacts/common/compat/CompatUtils.java
index 567f183..a394093 100644
--- a/src/com/android/contacts/common/compat/CompatUtils.java
+++ b/src/com/android/contacts/common/compat/CompatUtils.java
@@ -173,6 +173,16 @@
         return VERSION.SDK_INT >= 24;
     }
 
+
+    public static boolean isNougatMr1Compatible() {
+        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.N_MR1)
+                >= Build.VERSION_CODES.N_MR1;
+    }
+
+    public static boolean isLauncherShortcutCompatible() {
+        return isNougatMr1Compatible();
+    }
+
     /**
      * Determines if the given class is available. Can be used to check if system apis exist at
      * runtime.
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 8f67d95..4ab1953 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -64,9 +64,9 @@
 import android.provider.ContactsContract.CommonDataKinds.Website;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.DataUsageFeedback;
 import android.provider.ContactsContract.Directory;
 import android.provider.ContactsContract.DisplayNameSources;
-import android.provider.ContactsContract.DataUsageFeedback;
 import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.QuickContact;
 import android.provider.ContactsContract.RawContacts;
@@ -105,6 +105,7 @@
 
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.ContactsActivity;
+import com.android.contacts.DynamicShortcuts;
 import com.android.contacts.NfcHandler;
 import com.android.contacts.R;
 import com.android.contacts.activities.ContactEditorBaseActivity;
@@ -125,16 +126,18 @@
 import com.android.contacts.common.list.ShortcutIntentBuilder;
 import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
 import com.android.contacts.common.logging.Logger;
-import com.android.contacts.common.logging.ScreenEvent.ScreenType;
-import com.android.contacts.common.logging.QuickContactEvent.ContactType;
-import com.android.contacts.common.logging.QuickContactEvent.CardType;
 import com.android.contacts.common.logging.QuickContactEvent.ActionType;
+import com.android.contacts.common.logging.QuickContactEvent.CardType;
+import com.android.contacts.common.logging.QuickContactEvent.ContactType;
+import com.android.contacts.common.logging.ScreenEvent.ScreenType;
 import com.android.contacts.common.model.AccountTypeManager;
 import com.android.contacts.common.model.Contact;
 import com.android.contacts.common.model.ContactLoader;
 import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.ValuesDelta;
 import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.dataitem.CustomDataItem;
 import com.android.contacts.common.model.dataitem.DataItem;
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.android.contacts.common.model.dataitem.EmailDataItem;
@@ -149,10 +152,8 @@
 import com.android.contacts.common.model.dataitem.StructuredNameDataItem;
 import com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
 import com.android.contacts.common.model.dataitem.WebsiteDataItem;
-import com.android.contacts.common.model.dataitem.CustomDataItem;
-import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.common.util.ImplicitIntentsUtil;
 import com.android.contacts.common.util.DateUtils;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
 import com.android.contacts.common.util.MaterialColorMapUtils;
 import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
 import com.android.contacts.common.util.PermissionsUtil;
@@ -182,10 +183,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.lang.SecurityException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -258,6 +257,7 @@
 
     // Set true in {@link #onCreate} after orientation change for later use in processIntent().
     private boolean mIsRecreatedInstance;
+    private boolean mShortcutUsageReported = false;
 
     private boolean mShouldLog;
 
@@ -1267,6 +1267,7 @@
                 getIntent().getStringExtra(QuickContact.EXTRA_PRIORITIZED_MIMETYPE);
         final Uri oldLookupUri = mLookupUri;
 
+
         if (lookupUri == null) {
             finish();
             return;
@@ -2613,6 +2614,11 @@
                     return;
                 }
 
+                if (!mIsRecreatedInstance && !mShortcutUsageReported) {
+                    mShortcutUsageReported = true;
+                    DynamicShortcuts.reportShortcutUsed(QuickContactActivity.this,
+                            data.getLookupKey());
+                }
                 bindContactData(data);
 
             } finally {