Merge "New Spam-related options in call log entries." into ub-contactsdialer-b-dev
diff --git a/Android.mk b/Android.mk
index 47648db..20f3944 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,6 +23,12 @@
     $(contacts_common_dir)/res \
     $(phone_common_dir)/res
 
+src_dirs += \
+    src-N \
+    $(incallui_dir)/src-N \
+    $(contacts_common_dir)/src-N \
+    $(phone_common_dir)/src-N
+
 LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
 LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs)) \
     $(support_library_root_dir)/v7/cardview/res \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9d5af42..67161ad 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -17,8 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.dialer"
     coreApp="true"
-    android:versionCode="20314"
-    android:versionName="2.3.14">
+    android:versionCode="20401"
+    android:versionName="2.04.01">
 
     <uses-sdk
         android:minSdkVersion="23"
@@ -294,7 +294,8 @@
                   android:launchMode="singleInstance"
                   android:configChanges="keyboardHidden"
                   android:exported="false"
-                  android:screenOrientation="nosensor" >
+                  android:screenOrientation="nosensor"
+                  android:encryptionAware="true" >
         </activity>
 
         <!-- BroadcastReceiver for receiving Intents from Notification mechanism. -->
@@ -302,7 +303,8 @@
                   android:exported="false" />
 
         <service android:name="com.android.incallui.InCallServiceImpl"
-                 android:permission="android.permission.BIND_INCALL_SERVICE" >
+                 android:permission="android.permission.BIND_INCALL_SERVICE"
+                 android:encryptionAware="true" >
             <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
             <intent-filter>
                 <action android:name="android.telecom.InCallService"/>
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 95de268..469e72a 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -101,6 +101,14 @@
                             android:layout_marginEnd="@dimen/call_log_icon_margin"
                             android:layout_gravity="center_vertical" />
 
+                        <ImageView android:id="@+id/work_profile_icon"
+                            android:src="@drawable/ic_work_profile"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginEnd="@dimen/call_log_icon_margin"
+                            android:scaleType="center"
+                            android:visibility="gone" />
+
                         <TextView
                             android:id="@+id/call_location_and_date"
                             android:layout_width="wrap_content"
diff --git a/src-N/com/android/dialer/SdkSelectionUtils.java b/src-N/com/android/dialer/SdkSelectionUtils.java
new file mode 100644
index 0000000..ae7a631
--- /dev/null
+++ b/src-N/com/android/dialer/SdkSelectionUtils.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.dialer;
+
+/**
+ * Provides information for the SDK the app is built against.
+ * Specifically, information that change when the TARGET_N_SDK build flag is set in the makefile.
+ * This is not related to the targetSdkVersion value in AndroidManifest.xml.
+ *
+ * Usage case will be branching test code in src/, instead of swapping between src-N and src-pre-N.
+ */
+public class SdkSelectionUtils {
+
+    /**
+     * Whether the app is build against N SDK.
+     *
+     * Since Build.VERSION.SDK_INT remains 23 on N SDK for now, this is currently the only way to
+     * check if we are building with N SDK or other.
+     */
+    public static final boolean TARGET_N_SDK = true;
+}
diff --git a/src-pre-N/com/android/dialer/SdkSelectionUtils.java b/src-pre-N/com/android/dialer/SdkSelectionUtils.java
new file mode 100644
index 0000000..7e36b33
--- /dev/null
+++ b/src-pre-N/com/android/dialer/SdkSelectionUtils.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.dialer;
+
+/**
+ * Provides information for the SDK the app is built against.
+ * Specifically, information that change when the TARGET_N_SDK build flag is set in the makefile.
+ * This is not related to the targetSdkVersion value in AndroidManifest.xml.
+ *
+ * Usage case will be branching test code in src/, instead of using src-N/ and src-pre-N/
+ */
+public class SdkSelectionUtils {
+
+    /**
+     * Whether the app is build against N SDK.
+     *
+     * Since Build.VERSION.SDK_INT remains 23 on N SDK for now, this is currently the only way to
+     * check if we are building with N SDK or other.
+     */
+    public static final boolean TARGET_N_SDK = false;
+}
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index c045967..56e29a9 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -153,6 +153,8 @@
             final boolean canPlaceCallsTo =
                     PhoneNumberUtil.canPlaceCallsTo(mNumber, mDetails.numberPresentation);
             mCallButton.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
+            mCopyNumberActionItem.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
+            mBlockNumberActionItem.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
 
             final boolean isSipNumber = PhoneNumberUtil.isSipNumber(mNumber);
             final boolean isVoicemailNumber =
@@ -221,6 +223,7 @@
     private TextView mBlockNumberActionItem;
     private View mEditBeforeCallActionItem;
     private View mReportActionItem;
+    private View mCopyNumberActionItem;
 
     private Integer mBlockedNumberId;
 
@@ -279,8 +282,8 @@
         mReportActionItem = findViewById(R.id.call_detail_action_report);
         mReportActionItem.setOnClickListener(this);
 
-        View copyActionItem = findViewById(R.id.call_detail_action_copy);
-        copyActionItem.setOnClickListener(this);
+        mCopyNumberActionItem = findViewById(R.id.call_detail_action_copy);
+        mCopyNumberActionItem.setOnClickListener(this);
 
         if (getIntent().getBooleanExtra(EXTRA_FROM_NOTIFICATION, false)) {
             closeSystemDialogs();
diff --git a/src/com/android/dialer/FloatingActionButtonBehavior.java b/src/com/android/dialer/FloatingActionButtonBehavior.java
index 8a407bd..679c9a7 100644
--- a/src/com/android/dialer/FloatingActionButtonBehavior.java
+++ b/src/com/android/dialer/FloatingActionButtonBehavior.java
@@ -34,17 +34,14 @@
 
     @Override
     public boolean layoutDependsOn(CoordinatorLayout parent, FrameLayout child, View dependency) {
-        // This needs to return true to trigger the callback correctly.
-        return true;
+        return dependency instanceof SnackbarLayout;
     }
 
     @Override
     public boolean onDependentViewChanged(CoordinatorLayout parent, FrameLayout child,
             View dependency) {
-        if (dependency instanceof SnackbarLayout) {
-            float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
-            child.setTranslationY(translationY);
-        }
+        float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
+        child.setTranslationY(translationY);
         return true;
     }
 }
diff --git a/src/com/android/dialer/PhoneCallDetails.java b/src/com/android/dialer/PhoneCallDetails.java
index 71aa26d..b332b43 100644
--- a/src/com/android/dialer/PhoneCallDetails.java
+++ b/src/com/android/dialer/PhoneCallDetails.java
@@ -16,6 +16,7 @@
 
 package com.android.dialer;
 
+import com.android.contacts.common.ContactsUtils.UserType;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.dialer.calllog.PhoneNumberDisplayUtil;
 
@@ -101,6 +102,9 @@
     // Whether the contact number is a voicemail number.
     public boolean isVoicemail;
 
+    /** The {@link UserType} of the contact */
+    public @UserType long contactUserType;
+
     /**
      * If this is a voicemail, whether the message is read. For other types of calls, this defaults
      * to {@code true}.
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index dac50ff..af77d86 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -41,6 +41,7 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.contacts.common.util.PermissionsUtil;
@@ -55,6 +56,7 @@
 import com.android.dialer.logging.Logger;
 import com.android.dialer.util.PhoneNumberUtil;
 import com.android.dialer.voicemail.VoicemailPlaybackPresenter;
+import com.android.incallui.CallerInfo;
 
 import java.util.HashMap;
 
@@ -400,6 +402,7 @@
      * @param viewHolder The view corresponding to this entry.
      * @param position The position of the entry.
      */
+    @Override
     public void onBindViewHolder(ViewHolder viewHolder, int position) {
         Trace.beginSection("onBindViewHolder: " + position);
 
@@ -497,6 +500,7 @@
             details.photoUri = info.photoUri;
             details.sourceType = info.sourceType;
             details.objectId = info.objectId;
+            details.contactUserType = info.userType;
         }
 
         final CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder;
@@ -517,6 +521,8 @@
                 details.numberLabel);
         // Default case: an item in the call log.
         views.primaryActionView.setVisibility(View.VISIBLE);
+        views.workIconView.setVisibility(
+                details.contactUserType == ContactsUtils.USER_TYPE_WORK ? View.VISIBLE : View.GONE);
 
         // Check if the day group has changed and display a header if necessary.
         int currentGroup = getDayGroupForCall(views.rowId);
diff --git a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
index e5ee3bc..f76312d 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
@@ -102,6 +102,7 @@
     public View sendMessageView;
     public View detailsButtonView;
     public View callWithNoteButtonView;
+    public ImageView workIconView;
 
     /**
      * The row Id for the first call associated with the call log entry.  Used as a key for the
@@ -242,6 +243,7 @@
         this.callLogEntryView = callLogEntryView;
         this.dayGroupHeader = dayGroupHeader;
         this.primaryActionButtonView = primaryActionButtonView;
+        this.workIconView = (ImageView) rootView.findViewById(R.id.work_profile_icon);
 
         Resources resources = mContext.getResources();
         mPhotoSize = mContext.getResources().getDimensionPixelSize(R.dimen.contact_photo_size);
diff --git a/src/com/android/dialer/calllog/ContactInfo.java b/src/com/android/dialer/calllog/ContactInfo.java
index 30f60d9..1020d10 100644
--- a/src/com/android/dialer/calllog/ContactInfo.java
+++ b/src/com/android/dialer/calllog/ContactInfo.java
@@ -19,6 +19,7 @@
 import android.net.Uri;
 import android.text.TextUtils;
 
+import com.android.contacts.common.ContactsUtils.UserType;
 import com.android.contacts.common.util.UriUtils;
 import com.google.common.base.Objects;
 
@@ -46,6 +47,7 @@
     public Uri photoUri;
     public boolean isBadData;
     public String objectId;
+    public @UserType long userType;
 
     public static ContactInfo EMPTY = new ContactInfo();
 
@@ -80,6 +82,7 @@
         if (photoId != other.photoId) return false;
         if (!UriUtils.areEqual(photoUri, other.photoUri)) return false;
         if (!TextUtils.equals(objectId, other.objectId)) return false;
+        if (userType != other.userType) return false;
         return true;
     }
 
diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java
index 1fd2fad..e075b9b 100644
--- a/src/com/android/dialer/calllog/ContactInfoHelper.java
+++ b/src/com/android/dialer/calllog/ContactInfoHelper.java
@@ -32,6 +32,7 @@
 import android.util.Log;
 
 import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.compat.ContactsCompat;
 import com.android.contacts.common.util.Constants;
 import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.common.util.PhoneNumberHelper;
@@ -41,6 +42,7 @@
 import com.android.dialer.service.CachedNumberLookupService.CachedContactInfo;
 import com.android.dialer.util.TelecomUtil;
 import com.android.dialerbind.ObjectFactory;
+import com.android.incallui.CallerInfo;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -200,6 +202,9 @@
         info.photoId = phoneLookupCursor.getLong(PhoneQuery.PHOTO_ID);
         info.photoUri = UriUtils.parseUriOrNull(phoneLookupCursor.getString(PhoneQuery.PHOTO_URI));
         info.formattedNumber = null;
+        info.userType = ContactsUtils.determineUserType(null,
+                phoneLookupCursor.getLong(PhoneQuery.PERSON_ID));
+
         return info;
     }
 
diff --git a/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java b/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java
index 91cd3e1..09b42e9 100644
--- a/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java
+++ b/src/com/android/dialer/calllog/PhoneNumberDisplayUtil.java
@@ -78,7 +78,7 @@
         } else if (!TextUtils.isEmpty(number)) {
             return number.toString() + postDialDigits;
         } else {
-            return "";
+            return context.getResources().getString(R.string.unknown);
         }
     }
 
diff --git a/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java b/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java
index 06aca78..ff9b1be 100644
--- a/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java
+++ b/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java
@@ -134,7 +134,7 @@
                 new Listener() {
                     @Override
                     protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
-                        listener.onHasBlockedNumbers(cursor.getCount() > 0);
+                        listener.onHasBlockedNumbers(cursor != null && cursor.getCount() > 0);
                     }
                 },
                 getContentUri(null),
@@ -161,7 +161,7 @@
                 new Listener() {
                     @Override
                     protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
-                        if (cursor.getCount() != 1) {
+                        if (cursor == null || cursor.getCount() != 1) {
                             listener.onCheckComplete(null);
                             return;
                         }
@@ -246,9 +246,10 @@
         startQuery(NO_TOKEN, new Listener() {
             @Override
             public void onQueryComplete(int token, Object cookie, Cursor cursor) {
-                if (cursor.getCount() != 1) {
+                int rowsReturned = cursor == null ? 0 : cursor.getCount();
+                if (rowsReturned != 1) {
                     throw new SQLiteDatabaseCorruptException
-                            ("Returned " + cursor.getCount() + " rows for uri "
+                            ("Returned " + rowsReturned + " rows for uri "
                                     + uri + "where 1 expected.");
                 }
                 cursor.moveToFirst();
diff --git a/src/com/android/dialer/list/RegularSearchListAdapter.java b/src/com/android/dialer/list/RegularSearchListAdapter.java
index 748f4dc..4d8bb6d 100644
--- a/src/com/android/dialer/list/RegularSearchListAdapter.java
+++ b/src/com/android/dialer/list/RegularSearchListAdapter.java
@@ -21,6 +21,8 @@
 import android.text.TextUtils;
 
 import com.android.contacts.common.CallUtil;
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.compat.DirectoryCompat;
 import com.android.contacts.common.list.DirectoryPartition;
 import com.android.contacts.common.util.PhoneNumberHelper;
 import com.android.dialer.calllog.ContactInfo;
@@ -45,19 +47,21 @@
         CachedContactInfo cacheInfo = lookupService.buildCachedContactInfo(info);
         final Cursor item = (Cursor) getItem(position);
         if (item != null) {
+            final DirectoryPartition partition =
+                (DirectoryPartition) getPartition(getPartitionForPosition(position));
+            final long directoryId = partition.getDirectoryId();
+
             info.name = item.getString(PhoneQuery.DISPLAY_NAME);
             info.type = item.getInt(PhoneQuery.PHONE_TYPE);
             info.label = item.getString(PhoneQuery.PHONE_LABEL);
             info.number = item.getString(PhoneQuery.PHONE_NUMBER);
             final String photoUriStr = item.getString(PhoneQuery.PHOTO_URI);
             info.photoUri = photoUriStr == null ? null : Uri.parse(photoUriStr);
+            info.userType = DirectoryCompat.isEnterpriseDirectoryId(directoryId)
+                    ? ContactsUtils.USER_TYPE_WORK : ContactsUtils.USER_TYPE_CURRENT;
 
             cacheInfo.setLookupKey(item.getString(PhoneQuery.LOOKUP_KEY));
 
-            final int partitionIndex = getPartitionForPosition(position);
-            final DirectoryPartition partition =
-                (DirectoryPartition) getPartition(partitionIndex);
-            final long directoryId = partition.getDirectoryId();
             final String sourceName = partition.getLabel();
             if (isExtendedDirectory(directoryId)) {
                 cacheInfo.setExtendedSource(sourceName, directoryId);
diff --git a/tests/src-N/com/android/dialer/SdkSelectionUtilsTest.java b/tests/src-N/com/android/dialer/SdkSelectionUtilsTest.java
new file mode 100644
index 0000000..2950ea0
--- /dev/null
+++ b/tests/src-N/com/android/dialer/SdkSelectionUtilsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.dialer;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+// @formatter:off
+/**
+ * Run test with
+ * adb shell am instrument -e class com.android.dialer.SdkSelectionUtilsTest -w com.google.android.dialer.tests/android.test.InstrumentationTestRunner
+ */
+// @formatter:on
+@SmallTest
+public class SdkSelectionUtilsTest extends AndroidTestCase {
+
+    public void testTargetNSdk_True() {
+        assertTrue(SdkSelectionUtils.TARGET_N_SDK);
+    }
+}
\ No newline at end of file
diff --git a/tests/src-pre-N/com/android/dialer/SdkSelectionUtilsTest.java b/tests/src-pre-N/com/android/dialer/SdkSelectionUtilsTest.java
new file mode 100644
index 0000000..595f1cc
--- /dev/null
+++ b/tests/src-pre-N/com/android/dialer/SdkSelectionUtilsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.dialer;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+// @formatter:off
+/**
+ * Run test with
+ * adb shell am instrument -e class com.android.dialer.SdkSelectionUtilsTest -w com.google.android.dialer.tests/android.test.InstrumentationTestRunner
+ */
+// @formatter:on
+@SmallTest
+public class SdkSelectionUtilsTest extends AndroidTestCase {
+
+    public void testTargetNSdk_False() {
+        assertFalse(SdkSelectionUtils.TARGET_N_SDK);
+    }
+}
\ No newline at end of file