diff options
135 files changed, 848 insertions, 539 deletions
diff --git a/assets/quantum/res/drawable/quantum_ic_query_builder_vd_theme_24.xml b/assets/quantum/res/drawable/quantum_ic_query_builder_vd_theme_24.xml new file mode 100644 index 000000000..54fd54537 --- /dev/null +++ b/assets/quantum/res/drawable/quantum_ic_query_builder_vd_theme_24.xml @@ -0,0 +1,25 @@ +<!-- + ~ Copyright (C) 2018 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7L11,7v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/> +</vector> diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java index c819fecba..06f094d5e 100644 --- a/java/com/android/dialer/app/DialtactsActivity.java +++ b/java/com/android/dialer/app/DialtactsActivity.java @@ -46,6 +46,7 @@ import android.telecom.PhoneAccount; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; +import android.view.ActionMode; import android.view.DragEvent; import android.view.Gravity; import android.view.Menu; @@ -1532,7 +1533,7 @@ public class DialtactsActivity extends TransactionSafeActivity } @Override - public void onActionModeStateChanged(boolean isEnabled) { + public void onActionModeStateChanged(ActionMode mode, boolean isEnabled) { isMultiSelectModeEnabled = isEnabled; } diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java index c2c753e43..450e5eaa7 100644 --- a/java/com/android/dialer/app/calllog/CallLogAdapter.java +++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java @@ -178,7 +178,7 @@ public class CallLogAdapter extends GroupingListAdapter MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.actionbar_delete, menu); multiSelectRemoveView.showMultiSelectRemoveView(true); - actionModeStateChangedListener.onActionModeStateChanged(true); + actionModeStateChangedListener.onActionModeStateChanged(mode, true); return true; } @@ -216,7 +216,7 @@ public class CallLogAdapter extends GroupingListAdapter selectAllMode = false; deselectAllMode = false; multiSelectRemoveView.showMultiSelectRemoveView(false); - actionModeStateChangedListener.onActionModeStateChanged(false); + actionModeStateChangedListener.onActionModeStateChanged(null, false); notifyDataSetChanged(); } }; @@ -1511,7 +1511,7 @@ public class CallLogAdapter extends GroupingListAdapter /** Interface used to allow single tap multi select for contact photos. */ public interface OnActionModeStateChangedListener { - void onActionModeStateChanged(boolean isEnabled); + void onActionModeStateChanged(ActionMode mode, boolean isEnabled); boolean isActionModeStateEnabled(); } diff --git a/java/com/android/dialer/app/res/drawable-hdpi/empty_call_log.png b/java/com/android/dialer/app/res/drawable-hdpi/empty_call_log.png Binary files differindex d6f6daaab..b51b7b8d9 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/empty_call_log.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/empty_call_log.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/empty_speed_dial.png b/java/com/android/dialer/app/res/drawable-hdpi/empty_speed_dial.png Binary files differdeleted file mode 100644 index 3e9232fc9..000000000 --- a/java/com/android/dialer/app/res/drawable-hdpi/empty_speed_dial.png +++ /dev/null diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_menu_history_lt.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_menu_history_lt.png Binary files differindex a36323ca9..1c0c65458 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_menu_history_lt.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_menu_history_lt.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_mic_grey600.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_mic_grey600.png Binary files differindex 4b67cf71a..a392ff66b 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_mic_grey600.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_mic_grey600.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_not_interested_googblue_24dp.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_not_interested_googblue_24dp.png Binary files differindex 26a26f911..393a0c882 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_not_interested_googblue_24dp.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_not_interested_googblue_24dp.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_not_spam.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_not_spam.png Binary files differindex bf413f912..37caf38f4 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_not_spam.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_not_spam.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_phone_24dp.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_phone_24dp.png Binary files differindex b27dfba06..9d4148248 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_phone_24dp.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_phone_24dp.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_remove.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_remove.png Binary files differindex 1ee6adf8d..0af1e39fd 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_remove.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_remove.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_star.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_star.png Binary files differindex 62e1f8a6d..91c08cfe4 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_star.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_star.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/ic_unblock.png b/java/com/android/dialer/app/res/drawable-hdpi/ic_unblock.png Binary files differindex 03643b20d..177761068 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/ic_unblock.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/ic_unblock.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/old_ic_handle.png b/java/com/android/dialer/app/res/drawable-hdpi/old_ic_handle.png Binary files differindex 34310aa49..a1c248ce4 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/old_ic_handle.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/old_ic_handle.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/search_shadow.9.png b/java/com/android/dialer/app/res/drawable-hdpi/search_shadow.9.png Binary files differindex 3dc1c17f6..7e7c7c137 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/search_shadow.9.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/search_shadow.9.png diff --git a/java/com/android/dialer/app/res/drawable-hdpi/shadow_contact_photo.png b/java/com/android/dialer/app/res/drawable-hdpi/shadow_contact_photo.png Binary files differindex 44b06f261..1fa6c4aeb 100644 --- a/java/com/android/dialer/app/res/drawable-hdpi/shadow_contact_photo.png +++ b/java/com/android/dialer/app/res/drawable-hdpi/shadow_contact_photo.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/empty_call_log.png b/java/com/android/dialer/app/res/drawable-mdpi/empty_call_log.png Binary files differindex 3cd59b35b..a8d5a0c3c 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/empty_call_log.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/empty_call_log.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/empty_speed_dial.png b/java/com/android/dialer/app/res/drawable-mdpi/empty_speed_dial.png Binary files differdeleted file mode 100644 index 98152e0d3..000000000 --- a/java/com/android/dialer/app/res/drawable-mdpi/empty_speed_dial.png +++ /dev/null diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_menu_history_lt.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_menu_history_lt.png Binary files differindex 3597a5e82..4a87c9410 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/ic_menu_history_lt.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/ic_menu_history_lt.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_mic_grey600.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_mic_grey600.png Binary files differindex 2310c734a..f058bff88 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/ic_mic_grey600.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/ic_mic_grey600.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_not_spam.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_not_spam.png Binary files differindex b1f1c7efe..211baa90a 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/ic_not_spam.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/ic_not_spam.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_phone_24dp.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_phone_24dp.png Binary files differindex c1766b854..6539c3437 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/ic_phone_24dp.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/ic_phone_24dp.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_remove.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_remove.png Binary files differindex 2c134ea10..241a6a678 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/ic_remove.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/ic_remove.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_star.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_star.png Binary files differindex d2af0ba20..1f6366302 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/ic_star.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/ic_star.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/ic_unblock.png b/java/com/android/dialer/app/res/drawable-mdpi/ic_unblock.png Binary files differindex d80fb2f5c..9f303d9a0 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/ic_unblock.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/ic_unblock.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/old_ic_handle.png b/java/com/android/dialer/app/res/drawable-mdpi/old_ic_handle.png Binary files differindex 81a67ba6f..3671e9394 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/old_ic_handle.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/old_ic_handle.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/search_shadow.9.png b/java/com/android/dialer/app/res/drawable-mdpi/search_shadow.9.png Binary files differindex 0c33905cd..758ce8279 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/search_shadow.9.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/search_shadow.9.png diff --git a/java/com/android/dialer/app/res/drawable-mdpi/shadow_contact_photo.png b/java/com/android/dialer/app/res/drawable-mdpi/shadow_contact_photo.png Binary files differindex 8665d8303..5c802f946 100644 --- a/java/com/android/dialer/app/res/drawable-mdpi/shadow_contact_photo.png +++ b/java/com/android/dialer/app/res/drawable-mdpi/shadow_contact_photo.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/empty_call_log.png b/java/com/android/dialer/app/res/drawable-xhdpi/empty_call_log.png Binary files differindex 14ec04ba1..eabc83819 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/empty_call_log.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/empty_call_log.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/empty_speed_dial.png b/java/com/android/dialer/app/res/drawable-xhdpi/empty_speed_dial.png Binary files differdeleted file mode 100644 index a3a76751b..000000000 --- a/java/com/android/dialer/app/res/drawable-xhdpi/empty_speed_dial.png +++ /dev/null diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_menu_history_lt.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_menu_history_lt.png Binary files differindex 6b411cbc3..27dbebff3 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_menu_history_lt.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/ic_menu_history_lt.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_mic_grey600.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_mic_grey600.png Binary files differindex a9a83b329..e1d6a5c17 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_mic_grey600.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/ic_mic_grey600.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_not_spam.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_not_spam.png Binary files differindex 138f27cdb..8fdd43fdf 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_not_spam.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/ic_not_spam.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_phone_24dp.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_phone_24dp.png Binary files differindex 83167f4cd..8d250c8ad 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_phone_24dp.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/ic_phone_24dp.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_remove.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_remove.png Binary files differindex be81592ef..ac81f84f0 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_remove.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/ic_remove.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_star.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_star.png Binary files differindex 2071f42f2..19518848a 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_star.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/ic_star.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/ic_unblock.png b/java/com/android/dialer/app/res/drawable-xhdpi/ic_unblock.png Binary files differindex f7dfa21ac..c6e6595ce 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/ic_unblock.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/ic_unblock.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/old_ic_handle.png b/java/com/android/dialer/app/res/drawable-xhdpi/old_ic_handle.png Binary files differindex 0ad839286..36f3466a6 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/old_ic_handle.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/old_ic_handle.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/search_shadow.9.png b/java/com/android/dialer/app/res/drawable-xhdpi/search_shadow.9.png Binary files differindex 5667ab368..ad4528698 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/search_shadow.9.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/search_shadow.9.png diff --git a/java/com/android/dialer/app/res/drawable-xhdpi/shadow_contact_photo.png b/java/com/android/dialer/app/res/drawable-xhdpi/shadow_contact_photo.png Binary files differindex 8359a50e9..4e09fd712 100644 --- a/java/com/android/dialer/app/res/drawable-xhdpi/shadow_contact_photo.png +++ b/java/com/android/dialer/app/res/drawable-xhdpi/shadow_contact_photo.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/empty_call_log.png b/java/com/android/dialer/app/res/drawable-xxhdpi/empty_call_log.png Binary files differindex 501d7f1e2..ddb88237a 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/empty_call_log.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/empty_call_log.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/empty_speed_dial.png b/java/com/android/dialer/app/res/drawable-xxhdpi/empty_speed_dial.png Binary files differdeleted file mode 100644 index fb2ea5f15..000000000 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/empty_speed_dial.png +++ /dev/null diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_menu_history_lt.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_menu_history_lt.png Binary files differindex 779bc0620..75a633ce5 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_menu_history_lt.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_menu_history_lt.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_mic_grey600.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_mic_grey600.png Binary files differindex 07128dd82..726fc11ba 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_mic_grey600.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_mic_grey600.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_not_spam.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_not_spam.png Binary files differindex f699959cb..941ce8dea 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_not_spam.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_not_spam.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_phone_24dp.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_phone_24dp.png Binary files differindex 8fff728bb..9b366f702 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_phone_24dp.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_phone_24dp.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_remove.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_remove.png Binary files differindex 2722f23aa..9281ab914 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_remove.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_remove.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_star.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_star.png Binary files differindex f3c830435..94fd394f7 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_star.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_star.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_unblock.png b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_unblock.png Binary files differindex 828a4879f..52fce33fc 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/ic_unblock.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/ic_unblock.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/old_ic_handle.png b/java/com/android/dialer/app/res/drawable-xxhdpi/old_ic_handle.png Binary files differindex d07a1d057..269cb3810 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/old_ic_handle.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/old_ic_handle.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/search_shadow.9.png b/java/com/android/dialer/app/res/drawable-xxhdpi/search_shadow.9.png Binary files differindex ff55620d0..fc6f3bf5d 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/search_shadow.9.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/search_shadow.9.png diff --git a/java/com/android/dialer/app/res/drawable-xxhdpi/shadow_contact_photo.png b/java/com/android/dialer/app/res/drawable-xxhdpi/shadow_contact_photo.png Binary files differindex bfeb0ff53..f7b8d2d9a 100644 --- a/java/com/android/dialer/app/res/drawable-xxhdpi/shadow_contact_photo.png +++ b/java/com/android/dialer/app/res/drawable-xxhdpi/shadow_contact_photo.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/empty_call_log.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/empty_call_log.png Binary files differindex fbac1e40f..5704d753f 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/empty_call_log.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/empty_call_log.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_mic_grey600.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_mic_grey600.png Binary files differindex b7403ff22..d80da4bb4 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_mic_grey600.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_mic_grey600.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_not_spam.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_not_spam.png Binary files differindex 2a18de24e..d1634c13b 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_not_spam.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_not_spam.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_phone_24dp.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_phone_24dp.png Binary files differindex 30d141db5..71c48f111 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_phone_24dp.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_phone_24dp.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_unblock.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_unblock.png Binary files differindex 99a1842a2..01551e2fc 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_unblock.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/ic_unblock.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/nui_launcher_icon.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/nui_launcher_icon.png Binary files differindex 7845ebca4..b0bb8f59f 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/nui_launcher_icon.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/nui_launcher_icon.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/old_ic_handle.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/old_ic_handle.png Binary files differindex 72641c7ab..0a659982b 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/old_ic_handle.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/old_ic_handle.png diff --git a/java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.png b/java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.png Binary files differindex ff55620d0..fc6f3bf5d 100644 --- a/java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.png +++ b/java/com/android/dialer/app/res/drawable-xxxhdpi/search_shadow.9.png diff --git a/java/com/android/dialer/app/res/mipmap-hdpi/ic_launcher_phone.png b/java/com/android/dialer/app/res/mipmap-hdpi/ic_launcher_phone.png Binary files differindex 15c41423b..0d1769a78 100644 --- a/java/com/android/dialer/app/res/mipmap-hdpi/ic_launcher_phone.png +++ b/java/com/android/dialer/app/res/mipmap-hdpi/ic_launcher_phone.png diff --git a/java/com/android/dialer/app/res/mipmap-mdpi/ic_launcher_phone.png b/java/com/android/dialer/app/res/mipmap-mdpi/ic_launcher_phone.png Binary files differindex 3088f7502..667fc5deb 100644 --- a/java/com/android/dialer/app/res/mipmap-mdpi/ic_launcher_phone.png +++ b/java/com/android/dialer/app/res/mipmap-mdpi/ic_launcher_phone.png diff --git a/java/com/android/dialer/app/res/mipmap-xhdpi/ic_launcher_phone.png b/java/com/android/dialer/app/res/mipmap-xhdpi/ic_launcher_phone.png Binary files differindex e87de01fb..2298d0dcc 100644 --- a/java/com/android/dialer/app/res/mipmap-xhdpi/ic_launcher_phone.png +++ b/java/com/android/dialer/app/res/mipmap-xhdpi/ic_launcher_phone.png diff --git a/java/com/android/dialer/app/res/mipmap-xxhdpi/ic_launcher_phone.png b/java/com/android/dialer/app/res/mipmap-xxhdpi/ic_launcher_phone.png Binary files differindex b866b79a7..b269b5aa7 100644 --- a/java/com/android/dialer/app/res/mipmap-xxhdpi/ic_launcher_phone.png +++ b/java/com/android/dialer/app/res/mipmap-xxhdpi/ic_launcher_phone.png diff --git a/java/com/android/dialer/app/res/mipmap-xxxhdpi/ic_launcher_phone.png b/java/com/android/dialer/app/res/mipmap-xxxhdpi/ic_launcher_phone.png Binary files differindex 26f51f153..dbc76f340 100644 --- a/java/com/android/dialer/app/res/mipmap-xxxhdpi/ic_launcher_phone.png +++ b/java/com/android/dialer/app/res/mipmap-xxxhdpi/ic_launcher_phone.png diff --git a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java index 6cbaf4fe7..8746b2bf1 100644 --- a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java +++ b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java @@ -37,7 +37,7 @@ import com.android.dialer.preferredsim.PreferredSimModule; import com.android.dialer.preferredsim.suggestion.stub.StubSimSuggestionModule; import com.android.dialer.simulator.impl.SimulatorModule; import com.android.dialer.simulator.stub.StubSimulatorEnrichedCallModule; -import com.android.dialer.spam.StubSpamModule; +import com.android.dialer.spam.stub.StubSpamModule; import com.android.dialer.storage.StorageModule; import com.android.dialer.strictmode.impl.SystemStrictModeModule; import com.android.incallui.calllocation.stub.StubCallLocationModule; diff --git a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java index f4f7a0a3b..62b8ca251 100644 --- a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java +++ b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java @@ -37,7 +37,7 @@ import com.android.dialer.preferredsim.PreferredSimModule; import com.android.dialer.preferredsim.suggestion.stub.StubSimSuggestionModule; import com.android.dialer.simulator.impl.SimulatorModule; import com.android.dialer.simulator.stub.StubSimulatorEnrichedCallModule; -import com.android.dialer.spam.StubSpamModule; +import com.android.dialer.spam.stub.StubSpamModule; import com.android.dialer.storage.StorageModule; import com.android.dialer.strictmode.impl.SystemStrictModeModule; import com.android.incallui.calllocation.impl.CallLocationModule; diff --git a/java/com/android/dialer/callcomposer/cameraui/res/drawable-xhdpi/ic_capture.png b/java/com/android/dialer/callcomposer/cameraui/res/drawable-xhdpi/ic_capture.png Binary files differindex 4ec9f75e8..66f9f0503 100644 --- a/java/com/android/dialer/callcomposer/cameraui/res/drawable-xhdpi/ic_capture.png +++ b/java/com/android/dialer/callcomposer/cameraui/res/drawable-xhdpi/ic_capture.png diff --git a/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxhdpi/ic_capture.png b/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxhdpi/ic_capture.png Binary files differindex e2345dc86..4308defa3 100644 --- a/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxhdpi/ic_capture.png +++ b/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxhdpi/ic_capture.png diff --git a/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxxhdpi/ic_capture.png b/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxxhdpi/ic_capture.png Binary files differindex 3bab00984..53a2f1179 100644 --- a/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxxhdpi/ic_capture.png +++ b/java/com/android/dialer/callcomposer/cameraui/res/drawable-xxxhdpi/ic_capture.png diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java index a08b50eb8..1b66f5099 100644 --- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java +++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java @@ -62,11 +62,13 @@ import java.util.Arrays; import java.util.List; import java.util.Set; import javax.inject.Inject; +import javax.inject.Singleton; /** * Responsible for defining the rows in the annotated call log and maintaining the columns in it * which are derived from the system call log. */ +@Singleton @SuppressWarnings("MissingPermission") public class SystemCallLogDataSource implements CallLogDataSource { @@ -81,6 +83,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { private final Duo duo; @Nullable private Long lastTimestampProcessed; + private boolean isCallLogContentObserverRegistered = false; @Inject SystemCallLogDataSource( @@ -106,7 +109,6 @@ public class SystemCallLogDataSource implements CallLogDataSource { LogUtil.i("SystemCallLogDataSource.registerContentObservers", "no call log permissions"); return; } - // TODO(zachh): Need to somehow register observers if user enables permission after launch? // The system call log has a last updated timestamp, but deletes are physical (the "deleted" // column is unused). This means that we can't detect deletes without scanning the entire table, @@ -115,6 +117,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { appContext .getContentResolver() .registerContentObserver(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL, true, markDirtyObserver); + isCallLogContentObserverRegistered = true; if (!PermissionsUtil.hasAddVoicemailPermissions(appContext)) { LogUtil.i("SystemCallLogDataSource.registerContentObservers", "no add voicemail permissions"); @@ -129,6 +132,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { @Override public void unregisterContentObservers() { appContext.getContentResolver().unregisterContentObserver(markDirtyObserver); + isCallLogContentObserverRegistered = false; } @Override @@ -140,7 +144,6 @@ public class SystemCallLogDataSource implements CallLogDataSource { return null; }); - // TODO(zachh): Test re-enabling after deleting database like this. return Futures.transform( Futures.allAsList(deleteSharedPref, annotatedCallLogDatabaseHelper.delete()), unused -> null, @@ -154,6 +157,14 @@ public class SystemCallLogDataSource implements CallLogDataSource { @Override public ListenableFuture<Boolean> isDirty() { + // This can happen if the call log permission is enabled after the application is started. + if (!isCallLogContentObserverRegistered + && PermissionsUtil.hasCallLogReadPermissions(appContext)) { + registerContentObservers(); + // Consider the data source dirty because calls could have been missed while the content + // observer wasn't registered. + return Futures.immediateFuture(true); + } return backgroundExecutorService.submit(this::isDirtyInternal); } diff --git a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java index 1890b7433..2feed4068 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogFragment.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogFragment.java @@ -21,6 +21,7 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.support.v4.content.LocalBroadcastManager; @@ -41,18 +42,26 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.metrics.Metrics; import com.android.dialer.metrics.MetricsComponent; import com.android.dialer.metrics.jank.RecyclerViewJankLogger; +import com.android.dialer.util.PermissionsUtil; +import com.android.dialer.widget.EmptyContentView; +import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import java.util.Arrays; import java.util.concurrent.TimeUnit; /** The "new" call log fragment implementation, which is built on top of the annotated call log. */ public final class NewCallLogFragment extends Fragment implements LoaderCallbacks<Cursor> { + private static final int PHONE_PERMISSIONS_REQUEST_CODE = 1; + private static final int LOADER_ID = 0; + @VisibleForTesting static final long MARK_ALL_CALLS_READ_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3); private RecyclerView recyclerView; + private EmptyContentView emptyContentView; private RefreshAnnotatedCallLogReceiver refreshAnnotatedCallLogReceiver; private SupportUiListener<Cursor> coalesingAnnotatedCallLogListener; @@ -133,6 +142,22 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback * will be called but it is not visible. */ private void onFragmentShown() { + LoaderManager loaderManager = getLoaderManager(); + if (!PermissionsUtil.hasCallLogReadPermissions(getContext())) { + recyclerView.setVisibility(View.GONE); + emptyContentView.setVisibility(View.VISIBLE); + loaderManager.destroyLoader(LOADER_ID); + return; + } + + recyclerView.setVisibility(View.VISIBLE); + emptyContentView.setVisibility(View.GONE); + + // This can happen if permissions were not enabled when the fragment was created. + if (loaderManager.getLoader(LOADER_ID) == null) { + loaderManager.restartLoader(LOADER_ID, null, this); + } + registerRefreshAnnotatedCallLogReceiver(); CallLogComponent.get(getContext()) @@ -193,16 +218,53 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback new RecyclerViewJankLogger( MetricsComponent.get(getContext()).metrics(), Metrics.NEW_CALL_LOG_JANK_EVENT_NAME)); + emptyContentView = view.findViewById(R.id.new_call_log_empty_content_view); + configureEmptyContentView(); + coalesingAnnotatedCallLogListener = DialerExecutorComponent.get(getContext()) .createUiListener( getChildFragmentManager(), /* taskId = */ "NewCallLogFragment.coalescingAnnotatedCallLog"); - getLoaderManager().restartLoader(0, null, this); + + if (PermissionsUtil.hasCallLogReadPermissions(getContext())) { + getLoaderManager().restartLoader(LOADER_ID, null, this); + } return view; } + private void configureEmptyContentView() { + emptyContentView.setImage(R.drawable.quantum_ic_query_builder_vd_theme_24); + emptyContentView.setImageTint(R.color.empty_call_log_icon_tint_color, null); + emptyContentView.setDescription(R.string.new_call_log_permission_no_calllog); + emptyContentView.setActionLabel(com.android.dialer.widget.R.string.permission_single_turn_on); + emptyContentView.setActionClickedListener(new TurnOnPhonePermissions()); + } + + private class TurnOnPhonePermissions implements OnEmptyViewActionButtonClickedListener { + + @Override + public void onEmptyViewActionButtonClicked() { + if (getContext() == null) { + LogUtil.w("TurnOnPhonePermissions.onEmptyViewActionButtonClicked", "no context"); + return; + } + String[] deniedPermissions = + PermissionsUtil.getPermissionsCurrentlyDenied( + getContext(), PermissionsUtil.allPhoneGroupPermissionsUsedInDialer); + if (deniedPermissions.length > 0) { + LogUtil.i( + "TurnOnPhonePermissions.onEmptyViewActionButtonClicked", + "requesting permissions: %s", + Arrays.toString(deniedPermissions)); + // Don't implement onRequestPermissionsResult; instead rely on views being updated in + // #onFragmentShown. + requestPermissions(deniedPermissions, PHONE_PERMISSIONS_REQUEST_CODE); + } + } + } + private void registerRefreshAnnotatedCallLogReceiver() { LogUtil.enterBlock("NewCallLogFragment.registerRefreshAnnotatedCallLogReceiver"); diff --git a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml index 048d562d3..1a2ec22d6 100644 --- a/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml +++ b/java/com/android/dialer/calllog/ui/res/layout/new_call_log_fragment.xml @@ -15,11 +15,26 @@ ~ limitations under the License --> -<android.support.v7.widget.RecyclerView +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/new_call_log_recycler_view" - android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/background_dialer_white" - android:paddingBottom="@dimen/floating_action_button_list_bottom_padding" - android:clipToPadding="false"/> + android:layout_width="match_parent"> + + <android.support.v7.widget.RecyclerView + android:id="@+id/new_call_log_recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingBottom="@dimen/floating_action_button_list_bottom_padding" + android:background="@color/background_dialer_white" + android:clipToPadding="false"/> + + <com.android.dialer.widget.EmptyContentView + android:gravity="center_vertical" + android:id="@+id/new_call_log_empty_content_view" + android:background="@color/background_dialer_white" + android:layout_gravity="center" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:visibility="gone"/> + +</FrameLayout> diff --git a/java/com/android/dialer/calllog/ui/res/values/colors.xml b/java/com/android/dialer/calllog/ui/res/values/colors.xml index 0a6d512ef..002aaf959 100644 --- a/java/com/android/dialer/calllog/ui/res/values/colors.xml +++ b/java/com/android/dialer/calllog/ui/res/values/colors.xml @@ -21,4 +21,6 @@ <color name="call_type_icon_read_color">#757575</color> <color name="call_type_icon_unread_color">#D32F2F</color> + + <color name="empty_call_log_icon_tint_color">#E1E1E1</color> </resources>
\ No newline at end of file diff --git a/java/com/android/dialer/calllog/ui/res/values/strings.xml b/java/com/android/dialer/calllog/ui/res/values/strings.xml index ec8d59503..699dfe9a6 100644 --- a/java/com/android/dialer/calllog/ui/res/values/strings.xml +++ b/java/com/android/dialer/calllog/ui/res/values/strings.xml @@ -36,4 +36,7 @@ Google Duo video calling lets you chat with friends and family face-to-face. Data charges may apply. <xliff:g example="Learn More">%1$s</xliff:g> </string> + <!-- Shown as a prompt to turn on the phone permission to enable the call log [CHAR LIMIT=NONE]--> + <string name="new_call_log_permission_no_calllog">To see your call log, turn on the Phone permission.</string> + </resources> diff --git a/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_add_call.png b/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_add_call.png Binary files differindex 4e0d5649e..7bc443b5b 100755..100644 --- a/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_add_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_add_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_current_call.png b/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_current_call.png Binary files differindex 2cf41d598..dccddeb31 100755..100644 --- a/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_current_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_current_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_tt_keypad.png b/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_tt_keypad.png Binary files differindex 043685fd9..9ad63ff1f 100755..100644 --- a/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_tt_keypad.png +++ b/java/com/android/dialer/dialpadview/res/drawable-hdpi/ic_dialer_fork_tt_keypad.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_add_call.png b/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_add_call.png Binary files differindex 56ac2a33a..8b9634133 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_add_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_add_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_current_call.png b/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_current_call.png Binary files differindex 16a44a078..0bc00b68f 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_current_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_current_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_tt_keypad.png b/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_tt_keypad.png Binary files differindex 66df69eac..f4038cd03 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_tt_keypad.png +++ b/java/com/android/dialer/dialpadview/res/drawable-mdpi/ic_dialer_fork_tt_keypad.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_add_call.png b/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_add_call.png Binary files differindex aff140fcd..bf657b833 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_add_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_add_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_current_call.png b/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_current_call.png Binary files differindex 8975727e0..e8ad65af5 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_current_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_current_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_tt_keypad.png b/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_tt_keypad.png Binary files differindex 4d48ea9ea..b9b817bab 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_tt_keypad.png +++ b/java/com/android/dialer/dialpadview/res/drawable-xhdpi/ic_dialer_fork_tt_keypad.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_add_call.png b/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_add_call.png Binary files differindex 1657da4e2..4f042aa72 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_add_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_add_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_current_call.png b/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_current_call.png Binary files differindex f25cce695..81bece640 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_current_call.png +++ b/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_current_call.png diff --git a/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_tt_keypad.png b/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_tt_keypad.png Binary files differindex 7ac4d8b58..ed4717ba8 100644 --- a/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_tt_keypad.png +++ b/java/com/android/dialer/dialpadview/res/drawable-xxhdpi/ic_dialer_fork_tt_keypad.png diff --git a/java/com/android/dialer/main/impl/MainSearchController.java b/java/com/android/dialer/main/impl/MainSearchController.java index 7d476c8f6..fc4fc3dcb 100644 --- a/java/com/android/dialer/main/impl/MainSearchController.java +++ b/java/com/android/dialer/main/impl/MainSearchController.java @@ -115,6 +115,11 @@ public class MainSearchController implements SearchBarListener { this.toolbar = toolbar; this.toolbarShadow = toolbarShadow; this.fragmentContainer = fragmentContainer; + + dialpadFragment = + (DialpadFragment) activity.getFragmentManager().findFragmentByTag(DIALPAD_FRAGMENT_TAG); + searchFragment = + (NewSearchFragment) activity.getFragmentManager().findFragmentByTag(SEARCH_FRAGMENT_TAG); } /** Should be called if we're showing the dialpad because of a new ACTION_DIAL intent. */ diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java index 2d6b0a6e7..16f46c10f 100644 --- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java +++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java @@ -48,6 +48,7 @@ import android.telecom.PhoneAccountHandle; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.method.LinkMovementMethod; +import android.view.ActionMode; import android.view.DragEvent; import android.view.View; import android.widget.ImageView; @@ -255,6 +256,10 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen v -> { Logger.get(activity).logImpression(DialerImpression.Type.MAIN_CLICK_FAB_TO_OPEN_DIALPAD); searchController.showDialpad(true); + if (callLogAdapterOnActionModeStateChangedListener.isEnabled) { + LogUtil.i("OldMainActivityPeer.onFabClicked", "closing multiselect"); + callLogAdapterOnActionModeStateChangedListener.actionMode.finish(); + } }); MainToolbar toolbar = activity.findViewById(R.id.toolbar); @@ -798,9 +803,11 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen implements CallLogAdapter.OnActionModeStateChangedListener { private boolean isEnabled; + private ActionMode actionMode; @Override - public void onActionModeStateChanged(boolean isEnabled) { + public void onActionModeStateChanged(ActionMode actionMode, boolean isEnabled) { + this.actionMode = actionMode; this.isEnabled = isEnabled; } diff --git a/java/com/android/dialer/main/impl/res/drawable-xxxhdpi/nui_launcher_icon.png b/java/com/android/dialer/main/impl/res/drawable-xxxhdpi/nui_launcher_icon.png Binary files differindex 7845ebca4..b0bb8f59f 100644 --- a/java/com/android/dialer/main/impl/res/drawable-xxxhdpi/nui_launcher_icon.png +++ b/java/com/android/dialer/main/impl/res/drawable-xxxhdpi/nui_launcher_icon.png diff --git a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java index 29a0de56b..efd7ae6f1 100644 --- a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java +++ b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java @@ -47,7 +47,8 @@ public final class PhoneLookupInfoConsolidator { NameSource.CP2_EXTENDED_DIRECTORY, NameSource.PEOPLE_API, NameSource.CEQUINT, - NameSource.CNAP + NameSource.CNAP, + NameSource.PHONE_NUMBER_CACHE }) @interface NameSource { int NONE = 0; // used when none of the other sources can provide the name @@ -56,6 +57,7 @@ public final class PhoneLookupInfoConsolidator { int PEOPLE_API = 3; int CEQUINT = 4; int CNAP = 5; + int PHONE_NUMBER_CACHE = 6; } /** @@ -81,7 +83,8 @@ public final class PhoneLookupInfoConsolidator { NameSource.CP2_EXTENDED_DIRECTORY, NameSource.PEOPLE_API, NameSource.CEQUINT, - NameSource.CNAP); + NameSource.CNAP, + NameSource.PHONE_NUMBER_CACHE); private final @NameSource int nameSource; private final PhoneLookupInfo phoneLookupInfo; @@ -113,6 +116,13 @@ public final class PhoneLookupInfoConsolidator { return ContactSource.Type.SOURCE_TYPE_CEQUINT_CALLER_ID; case NameSource.CNAP: return ContactSource.Type.SOURCE_TYPE_CNAP; + case NameSource.PHONE_NUMBER_CACHE: + ContactSource.Type sourceType = + ContactSource.Type.forNumber(phoneLookupInfo.getMigratedInfo().getSourceType()); + if (sourceType == null) { + sourceType = ContactSource.Type.UNKNOWN_SOURCE_TYPE; + } + return sourceType; case NameSource.NONE: return ContactSource.Type.UNKNOWN_SOURCE_TYPE; default: @@ -155,6 +165,8 @@ public final class PhoneLookupInfoConsolidator { return phoneLookupInfo.getCequintInfo().getName(); case NameSource.CNAP: return phoneLookupInfo.getCnapInfo().getName(); + case NameSource.PHONE_NUMBER_CACHE: + return phoneLookupInfo.getMigratedInfo().getName(); case NameSource.NONE: return ""; default: @@ -176,6 +188,8 @@ public final class PhoneLookupInfoConsolidator { return Assert.isNotNull(firstDefaultCp2Contact).getPhotoThumbnailUri(); case NameSource.CP2_EXTENDED_DIRECTORY: return Assert.isNotNull(firstExtendedCp2Contact).getPhotoThumbnailUri(); + case NameSource.PHONE_NUMBER_CACHE: + return phoneLookupInfo.getMigratedInfo().getPhotoUri(); case NameSource.PEOPLE_API: case NameSource.CEQUINT: case NameSource.CNAP: @@ -202,6 +216,8 @@ public final class PhoneLookupInfoConsolidator { return Assert.isNotNull(firstExtendedCp2Contact).getPhotoUri(); case NameSource.CEQUINT: return phoneLookupInfo.getCequintInfo().getPhotoUri(); + case NameSource.PHONE_NUMBER_CACHE: + return phoneLookupInfo.getMigratedInfo().getPhotoUri(); case NameSource.PEOPLE_API: case NameSource.CNAP: case NameSource.NONE: @@ -222,6 +238,7 @@ public final class PhoneLookupInfoConsolidator { return Math.max(Assert.isNotNull(firstDefaultCp2Contact).getPhotoId(), 0); case NameSource.CP2_EXTENDED_DIRECTORY: return Math.max(Assert.isNotNull(firstExtendedCp2Contact).getPhotoId(), 0); + case NameSource.PHONE_NUMBER_CACHE: case NameSource.PEOPLE_API: case NameSource.CEQUINT: case NameSource.CNAP: @@ -246,6 +263,7 @@ public final class PhoneLookupInfoConsolidator { return Assert.isNotNull(firstExtendedCp2Contact).getLookupUri(); case NameSource.PEOPLE_API: return Assert.isNotNull(phoneLookupInfo.getPeopleApiInfo().getLookupUri()); + case NameSource.PHONE_NUMBER_CACHE: case NameSource.CEQUINT: case NameSource.CNAP: case NameSource.NONE: @@ -270,6 +288,8 @@ public final class PhoneLookupInfoConsolidator { return Assert.isNotNull(firstDefaultCp2Contact).getLabel(); case NameSource.CP2_EXTENDED_DIRECTORY: return Assert.isNotNull(firstExtendedCp2Contact).getLabel(); + case NameSource.PHONE_NUMBER_CACHE: + return phoneLookupInfo.getMigratedInfo().getLabel(); case NameSource.PEOPLE_API: case NameSource.CEQUINT: case NameSource.CNAP: @@ -296,6 +316,7 @@ public final class PhoneLookupInfoConsolidator { case NameSource.CP2_EXTENDED_DIRECTORY: case NameSource.PEOPLE_API: case NameSource.CNAP: + case NameSource.PHONE_NUMBER_CACHE: case NameSource.NONE: return ""; default: @@ -309,8 +330,21 @@ public final class PhoneLookupInfoConsolidator { * returns whether the number belongs to a business place. */ public boolean isBusiness() { - return phoneLookupInfo.hasPeopleApiInfo() - && phoneLookupInfo.getPeopleApiInfo().getInfoType() == InfoType.NEARBY_BUSINESS; + switch (nameSource) { + case NameSource.PEOPLE_API: + return phoneLookupInfo.getPeopleApiInfo().getInfoType() == InfoType.NEARBY_BUSINESS; + case NameSource.PHONE_NUMBER_CACHE: + return phoneLookupInfo.getMigratedInfo().getIsBusiness(); + case NameSource.CP2_DEFAULT_DIRECTORY: + case NameSource.CP2_EXTENDED_DIRECTORY: + case NameSource.CEQUINT: + case NameSource.CNAP: + case NameSource.NONE: + return false; + default: + throw Assert.createUnsupportedOperationFailException( + String.format("Unsupported name source: %s", nameSource)); + } } /** @@ -366,6 +400,7 @@ public final class PhoneLookupInfoConsolidator { case NameSource.CP2_EXTENDED_DIRECTORY: case NameSource.CEQUINT: case NameSource.CNAP: + case NameSource.PHONE_NUMBER_CACHE: case NameSource.NONE: return false; case NameSource.PEOPLE_API: @@ -390,6 +425,7 @@ public final class PhoneLookupInfoConsolidator { case NameSource.PEOPLE_API: case NameSource.CEQUINT: case NameSource.CNAP: + case NameSource.PHONE_NUMBER_CACHE: case NameSource.NONE: return false; default: @@ -452,6 +488,11 @@ public final class PhoneLookupInfoConsolidator { return NameSource.CNAP; } break; + case NameSource.PHONE_NUMBER_CACHE: + if (!phoneLookupInfo.getMigratedInfo().getName().isEmpty()) { + return NameSource.PHONE_NUMBER_CACHE; + } + break; default: throw Assert.createUnsupportedOperationFailException( String.format("Unsupported name source: %s", nameSource)); diff --git a/java/com/android/dialer/phonelookup/phone_lookup_info.proto b/java/com/android/dialer/phonelookup/phone_lookup_info.proto index 9e9dfa918..f5ab5f0a9 100644 --- a/java/com/android/dialer/phonelookup/phone_lookup_info.proto +++ b/java/com/android/dialer/phonelookup/phone_lookup_info.proto @@ -14,7 +14,7 @@ package com.android.dialer.phonelookup; // "cp2_info_in_default_directory" corresponds to class // Cp2DefaultDirectoryPhoneLookup, and class Cp2DefaultDirectoryPhoneLookup // alone is responsible for populating it. -// Next ID: 10 +// Next ID: 11 message PhoneLookupInfo { // Information about a PhoneNumber retrieved from CP2. message Cp2Info { @@ -182,4 +182,19 @@ message PhoneLookupInfo { optional bool is_emergency_number = 1; } optional EmergencyInfo emergency_info = 9; + + // Information cached in the old calllog + message MigratedInfo { + // The display name + optional string name = 1; + // Display label, i.e. "Home", "Mobile" + optional string label = 2; + + optional string photo_uri = 3; + + optional bool is_business = 4; + // ContactSource.Type + optional int32 source_type = 5; + } + optional MigratedInfo migrated_info = 10; }
\ No newline at end of file diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-hdpi/business_asset.png b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-hdpi/business_asset.png Binary files differindex 8164c9a3e..062bba506 100644 --- a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-hdpi/business_asset.png +++ b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-hdpi/business_asset.png diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-mdpi/business_asset.png b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-mdpi/business_asset.png Binary files differindex e749e579e..60d84970c 100644 --- a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-mdpi/business_asset.png +++ b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-mdpi/business_asset.png diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xhdpi/business_asset.png b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xhdpi/business_asset.png Binary files differindex 6014f6801..e8a4e5de8 100644 --- a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xhdpi/business_asset.png +++ b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xhdpi/business_asset.png diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxhdpi/business_asset.png b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxhdpi/business_asset.png Binary files differindex 0dc4b4c89..73b716c8e 100644 --- a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxhdpi/business_asset.png +++ b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxhdpi/business_asset.png diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxxhdpi/business_asset.png b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxxhdpi/business_asset.png Binary files differindex ef7630302..b243f7182 100644 --- a/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxxhdpi/business_asset.png +++ b/java/com/android/dialer/searchfragment/nearbyplaces/res/drawable-xxxhdpi/business_asset.png diff --git a/java/com/android/dialer/simulator/SimulatorComponent.java b/java/com/android/dialer/simulator/SimulatorComponent.java index 6fa3f0cb1..ff75e9fed 100644 --- a/java/com/android/dialer/simulator/SimulatorComponent.java +++ b/java/com/android/dialer/simulator/SimulatorComponent.java @@ -18,6 +18,7 @@ package com.android.dialer.simulator; import android.content.Context; import com.android.dialer.inject.HasRootComponent; +import com.android.dialer.inject.IncludeInDialerRoot; import dagger.Subcomponent; /** Subcomponent that can be used to access the simulator implementation. */ @@ -36,6 +37,7 @@ public abstract class SimulatorComponent { } /** Used to refer to the root application component. */ + @IncludeInDialerRoot public interface HasComponent { SimulatorComponent simulatorComponent(); } diff --git a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java index 81a3d30de..8e794f051 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java +++ b/java/com/android/dialer/simulator/impl/SimulatorConferenceCreator.java @@ -32,7 +32,7 @@ import java.util.ArrayList; import java.util.Locale; /** Creates a conference with a given number of participants. */ -final class SimulatorConferenceCreator +public final class SimulatorConferenceCreator implements SimulatorConnectionService.Listener, SimulatorConnection.Listener, SimulatorConference.Listener { @@ -53,7 +53,12 @@ final class SimulatorConferenceCreator simulatorConnectionsBank = SimulatorComponent.get(context).getSimulatorConnectionsBank(); } - void start(int callCount) { + /** + * Starts to create certain number of calls to form a conference call. + * + * @param callCount the number of calls in conference to create. + */ + public void start(int callCount) { onNewIncomingConnectionEnabled = true; SimulatorConnectionService.addListener(this); if (conferenceType == Simulator.CONFERENCE_TYPE_VOLTE) { diff --git a/java/com/android/dialer/simulator/impl/SimulatorImpl.java b/java/com/android/dialer/simulator/impl/SimulatorImpl.java index c8b8af92e..44f8e118b 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorImpl.java +++ b/java/com/android/dialer/simulator/impl/SimulatorImpl.java @@ -22,6 +22,7 @@ import com.android.dialer.buildtype.BuildType; import com.android.dialer.buildtype.BuildType.Type; import com.android.dialer.common.LogUtil; import com.android.dialer.simulator.Simulator; +import com.android.dialer.simulator.portal.SimulatorMainPortal; import javax.inject.Inject; /** The entry point for the simulator feature. */ @@ -39,7 +40,7 @@ final class SimulatorImpl implements Simulator { @Override public ActionProvider getActionProvider(AppCompatActivity activity) { - return SimulatorMainMenu.getActionProvider(activity); + return new SimulatorMainPortal(activity).getActionProvider(); } @Override diff --git a/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java b/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java index b8556156b..52d7352ac 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java +++ b/java/com/android/dialer/simulator/impl/SimulatorMissedCallCreator.java @@ -30,14 +30,14 @@ import com.android.dialer.common.concurrent.ThreadUtil; * notifications instead of writing to the call log directly. This makes the simulator behave more * like the real application. */ -final class SimulatorMissedCallCreator implements SimulatorConnectionService.Listener { +public final class SimulatorMissedCallCreator implements SimulatorConnectionService.Listener { private static final String EXTRA_CALL_COUNT = "call_count"; private static final String EXTRA_IS_MISSED_CALL_CONNECTION = "is_missed_call_connection"; private static final int DISCONNECT_DELAY_MILLIS = 1000; private final Context context; - SimulatorMissedCallCreator(@NonNull Context context) { + public SimulatorMissedCallCreator(@NonNull Context context) { this.context = Assert.isNotNull(context); } diff --git a/java/com/android/dialer/simulator/impl/SimulatorNotifications.java b/java/com/android/dialer/simulator/impl/SimulatorNotifications.java deleted file mode 100644 index bd17b7ff8..000000000 --- a/java/com/android/dialer/simulator/impl/SimulatorNotifications.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2017 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.simulator.impl; - -import android.content.ContentValues; -import android.content.Context; -import android.provider.VoicemailContract.Voicemails; -import android.support.annotation.NonNull; -import android.view.ActionProvider; -import com.android.dialer.common.LogUtil; -import com.android.dialer.databasepopulator.VoicemailPopulator; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** Implements the simulator submenu. */ -final class SimulatorNotifications { - private static final int NOTIFICATION_COUNT = 12; - - static ActionProvider getActionProvider(@NonNull Context context) { - return new SimulatorSubMenu(context) - .addItem( - "Missed calls", () -> new SimulatorMissedCallCreator(context).start(NOTIFICATION_COUNT)) - .addItem("Voicemails", () -> addVoicemailNotifications(context)); - } - - private static void addVoicemailNotifications(@NonNull Context context) { - LogUtil.enterBlock("SimulatorNotifications.addVoicemailNotifications"); - List<ContentValues> voicemails = new ArrayList<>(); - for (int i = NOTIFICATION_COUNT; i > 0; i--) { - VoicemailPopulator.Voicemail voicemail = - VoicemailPopulator.Voicemail.builder() - .setPhoneNumber(String.format("+%d", i)) - .setTranscription(String.format("Short transcript %d", i)) - .setDurationSeconds(60) - .setIsRead(false) - .setPhoneAccountComponentName("") - .setTimeMillis(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(i)) - .build(); - voicemails.add(voicemail.getAsContentValues(context)); - } - context - .getContentResolver() - .bulkInsert( - Voicemails.buildSourceUri(context.getPackageName()), - voicemails.toArray(new ContentValues[voicemails.size()])); - } -} diff --git a/java/com/android/dialer/simulator/impl/SimulatorRttCall.java b/java/com/android/dialer/simulator/impl/SimulatorRttCall.java index 352b9e4ef..afd897775 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorRttCall.java +++ b/java/com/android/dialer/simulator/impl/SimulatorRttCall.java @@ -21,7 +21,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.telecom.Connection; import android.telecom.DisconnectCause; -import android.view.ActionProvider; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.ThreadUtil; @@ -29,28 +28,21 @@ import com.android.dialer.simulator.Simulator; import com.android.dialer.simulator.Simulator.Event; /** Entry point in the simulator to create voice calls. */ -final class SimulatorRttCall +public final class SimulatorRttCall implements SimulatorConnectionService.Listener, SimulatorConnection.Listener { @NonNull private final Context context; @Nullable private String connectionTag; private RttChatBot rttChatBot; - static ActionProvider getActionProvider(@NonNull Context context) { - return new SimulatorSubMenu(context) - .addItem("Incoming call", () -> new SimulatorRttCall(context).addNewIncomingCall(false)) - .addItem("Outgoing call", () -> new SimulatorRttCall(context).addNewOutgoingCall()) - .addItem("Emergency call", () -> new SimulatorRttCall(context).addNewEmergencyCall()); - } - - private SimulatorRttCall(@NonNull Context context) { + public SimulatorRttCall(@NonNull Context context) { this.context = Assert.isNotNull(context); SimulatorConnectionService.addListener(this); SimulatorConnectionService.addListener( new SimulatorConferenceCreator(context, Simulator.CONFERENCE_TYPE_GSM)); } - private void addNewIncomingCall(boolean isSpam) { + public void addNewIncomingCall(boolean isSpam) { String callerId = isSpam ? "+1-661-778-3020" /* Blacklisted custom spam number */ @@ -60,14 +52,14 @@ final class SimulatorRttCall context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT); } - private void addNewOutgoingCall() { + public void addNewOutgoingCall() { String callerId = "+55-31-2128-6800"; // Brazil office. connectionTag = SimulatorSimCallManager.addNewOutgoingCall( context, callerId, SimulatorSimCallManager.CALL_TYPE_RTT); } - private void addNewEmergencyCall() { + public void addNewEmergencyCall() { String callerId = "911"; connectionTag = SimulatorSimCallManager.addNewIncomingCall( diff --git a/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java index c56afb21f..0296ace4b 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java +++ b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java @@ -64,7 +64,7 @@ public class SimulatorSimCallManager { private static final String EXTRA_CONNECTION_TAG = "connection_tag"; private static final String EXTRA_CONNECTION_CALL_TYPE = "connection_call_type"; - static void register(@NonNull Context context) { + public static void register(@NonNull Context context) { LogUtil.enterBlock("SimulatorSimCallManager.register"); Assert.isNotNull(context); StrictModeUtils.bypass( @@ -75,7 +75,7 @@ public class SimulatorSimCallManager { }); } - static void unregister(@NonNull Context context) { + public static void unregister(@NonNull Context context) { LogUtil.enterBlock("SimulatorSimCallManager.unregister"); Assert.isNotNull(context); StrictModeUtils.bypass( diff --git a/java/com/android/dialer/simulator/impl/SimulatorSubMenu.java b/java/com/android/dialer/simulator/impl/SimulatorSubMenu.java deleted file mode 100644 index 64a2e7265..000000000 --- a/java/com/android/dialer/simulator/impl/SimulatorSubMenu.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2017 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.simulator.impl; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.ActionProvider; -import android.view.MenuItem; -import android.view.SubMenu; -import android.view.View; -import com.android.dialer.common.Assert; -import java.util.ArrayList; -import java.util.List; - -/** Makes it easier to create submenus in the simulator. */ -final class SimulatorSubMenu extends ActionProvider { - List<Item> items = new ArrayList<>(); - - SimulatorSubMenu(@NonNull Context context) { - super(Assert.isNotNull(context)); - } - - SimulatorSubMenu addItem(@NonNull String title, @NonNull Runnable clickHandler) { - items.add(new Item(title, clickHandler)); - return this; - } - - SimulatorSubMenu addItem(@NonNull String title, @NonNull ActionProvider actionProvider) { - items.add(new Item(title, actionProvider)); - return this; - } - - @Override - public View onCreateActionView() { - return null; - } - - @Override - public View onCreateActionView(MenuItem forItem) { - return null; - } - - @Override - public boolean hasSubMenu() { - return true; - } - - @Override - public void onPrepareSubMenu(SubMenu subMenu) { - super.onPrepareSubMenu(subMenu); - subMenu.clear(); - - for (Item item : items) { - if (item.clickHandler != null) { - subMenu - .add(item.title) - .setOnMenuItemClickListener( - (i) -> { - item.clickHandler.run(); - return true; - }); - } else { - subMenu.add(item.title).setActionProvider(item.actionProvider); - } - } - } - - private static final class Item { - @NonNull final String title; - @Nullable final Runnable clickHandler; - @Nullable final ActionProvider actionProvider; - - Item(@NonNull String title, @NonNull Runnable clickHandler) { - this.title = Assert.isNotNull(title); - this.clickHandler = Assert.isNotNull(clickHandler); - actionProvider = null; - } - - Item(@NonNull String title, @NonNull ActionProvider actionProvider) { - this.title = Assert.isNotNull(title); - this.clickHandler = null; - this.actionProvider = Assert.isNotNull(actionProvider); - } - } -} diff --git a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java b/java/com/android/dialer/simulator/impl/SimulatorUtils.java index ba2b55802..9e46f5aa9 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorMainMenu.java +++ b/java/com/android/dialer/simulator/impl/SimulatorUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 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. @@ -16,73 +16,35 @@ package com.android.dialer.simulator.impl; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.provider.VoicemailContract; +import android.provider.VoicemailContract.Voicemails; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.view.ActionProvider; +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.databasepopulator.BlockedBumberPopulator; import com.android.dialer.databasepopulator.CallLogPopulator; import com.android.dialer.databasepopulator.ContactsPopulator; import com.android.dialer.databasepopulator.VoicemailPopulator; -import com.android.dialer.enrichedcall.simulator.EnrichedCallSimulatorActivity; import com.android.dialer.persistentlog.PersistentLogger; import com.android.dialer.preferredsim.PreferredSimFallbackContract; -import com.android.dialer.simulator.SimulatorComponent; - -/** Implements the top level simulator menu. */ -final class SimulatorMainMenu { - - static ActionProvider getActionProvider(@NonNull AppCompatActivity activity) { - SimulatorSubMenu simulatorSubMenu = new SimulatorSubMenu(activity.getApplicationContext()); - simulatorSubMenu - .addItem("Voice call", SimulatorVoiceCall.getActionProvider(activity)) - .addItem("Rtt call", SimulatorRttCall.getActionProvider(activity.getApplicationContext())) - .addItem( - "IMS video", SimulatorVideoCall.getActionProvider(activity.getApplicationContext())) - .addItem( - "Notifications", - SimulatorNotifications.getActionProvider(activity.getApplicationContext())) - .addItem("Populate database", () -> populateDatabase(activity.getApplicationContext())) - .addItem("Populate voicemail", () -> populateVoicemail(activity.getApplicationContext())) - .addItem( - "Fast populate database", () -> fastPopulateDatabase(activity.getApplicationContext())) - .addItem( - "Fast populate voicemail database", - () -> populateVoicemailFast(activity.getApplicationContext())) - .addItem("Clean database", () -> cleanDatabase(activity.getApplicationContext())) - .addItem("clear preferred SIM", () -> clearPreferredSim(activity.getApplicationContext())) - .addItem("Sync voicemail", () -> syncVoicemail(activity.getApplicationContext())) - .addItem("Share persistent log", () -> sharePersistentLog(activity.getApplicationContext())) - .addItem( - "Enriched call simulator", - () -> - activity.startActivity( - EnrichedCallSimulatorActivity.newIntent(activity.getApplicationContext()))) - .addItem( - "Enable simulator mode", - () -> { - SimulatorComponent.get(activity.getApplicationContext()) - .getSimulator() - .enableSimulatorMode(); - SimulatorSimCallManager.register(activity.getApplicationContext()); - }) - .addItem( - "Disable simulator mode", - () -> { - SimulatorComponent.get(activity.getApplicationContext()) - .getSimulator() - .disableSimulatorMode(); - SimulatorSimCallManager.unregister(activity.getApplicationContext()); - }); - return simulatorSubMenu; - } +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +/** Contains utilities used often in test workflow. */ +public class SimulatorUtils { + + public static final int NOTIFICATION_COUNT_FEW = 1; + public static final int NOTIFICATION_COUNT = 12; - private static void populateDatabase(@NonNull Context context) { + /** Populates contacts database with predefined contacts entries. */ + public static void populateDatabase(@NonNull Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() .createNonUiTaskBuilder(new PopulateDatabaseWorker()) @@ -90,7 +52,8 @@ final class SimulatorMainMenu { .executeSerial(new PopulateDatabaseWorkerInput(context, false)); } - private static void populateVoicemail(@NonNull Context context) { + /** Populates voicemail database with predefined voicemail entries. */ + public static void populateVoicemail(@NonNull Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() .createNonUiTaskBuilder(new PopulateVoicemailWorker()) @@ -98,7 +61,8 @@ final class SimulatorMainMenu { .executeSerial(new PopulateDatabaseWorkerInput(context, false)); } - private static void populateVoicemailFast(@NonNull Context context) { + /** Populates voicemail database with only few predefined voicemail entries. */ + public static void populateVoicemailFast(@NonNull Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() .createNonUiTaskBuilder(new PopulateVoicemailWorker()) @@ -106,17 +70,8 @@ final class SimulatorMainMenu { .executeSerial(new PopulateDatabaseWorkerInput(context, true)); } - private static class PopulateVoicemailWorker - implements Worker<PopulateDatabaseWorkerInput, Void> { - @Nullable - @Override - public Void doInBackground(PopulateDatabaseWorkerInput input) { - VoicemailPopulator.populateVoicemail(input.context, input.fastMode); - return null; - } - } - - private static void fastPopulateDatabase(@NonNull Context context) { + /** Populates contacts database with only few predefined contacts entries. */ + public static void fastPopulateDatabase(@NonNull Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() .createNonUiTaskBuilder(new PopulateDatabaseWorker()) @@ -124,7 +79,8 @@ final class SimulatorMainMenu { .executeSerial(new PopulateDatabaseWorkerInput(context, true)); } - private static void cleanDatabase(@NonNull Context context) { + /** Clean contacts database. */ + public static void cleanDatabase(@NonNull Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() .createNonUiTaskBuilder(new CleanDatabaseWorker()) @@ -132,7 +88,8 @@ final class SimulatorMainMenu { .executeSerial(context); } - private static void clearPreferredSim(Context context) { + /** Clear preference over sim. */ + public static void clearPreferredSim(Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() .createNonUiTaskBuilder(new ClearPreferredSimWorker()) @@ -140,12 +97,13 @@ final class SimulatorMainMenu { .executeSerial(context); } - private static void syncVoicemail(@NonNull Context context) { + /** Sync voicemail by sending intents to system. */ + public static void syncVoicemail(@NonNull Context context) { Intent intent = new Intent(VoicemailContract.ACTION_SYNC_VOICEMAIL); context.sendBroadcast(intent); } - private static void sharePersistentLog(@NonNull Context context) { + public static void sharePersistentLog(@NonNull Context context) { DialerExecutorComponent.get(context) .dialerExecutorFactory() .createNonUiTaskBuilder(new ShareLogWorker()) @@ -162,7 +120,37 @@ final class SimulatorMainMenu { .executeSerial(null); } - private SimulatorMainMenu() {} + public static void addVoicemailNotifications(@NonNull Context context, int notificationNum) { + LogUtil.enterBlock("SimulatorNotifications.addVoicemailNotifications"); + List<ContentValues> voicemails = new ArrayList<>(); + for (int i = notificationNum; i > 0; i--) { + VoicemailPopulator.Voicemail voicemail = + VoicemailPopulator.Voicemail.builder() + .setPhoneNumber(String.format(Locale.ENGLISH, "+%d", i)) + .setTranscription(String.format(Locale.ENGLISH, "Short transcript %d", i)) + .setDurationSeconds(60) + .setIsRead(false) + .setPhoneAccountComponentName("") + .setTimeMillis(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(i)) + .build(); + voicemails.add(voicemail.getAsContentValues(context)); + } + context + .getContentResolver() + .bulkInsert( + Voicemails.buildSourceUri(context.getPackageName()), + voicemails.toArray(new ContentValues[voicemails.size()])); + } + + private static class PopulateVoicemailWorker + implements Worker<PopulateDatabaseWorkerInput, Void> { + @Nullable + @Override + public Void doInBackground(PopulateDatabaseWorkerInput input) { + VoicemailPopulator.populateVoicemail(input.context, input.fastMode); + return null; + } + } private static class PopulateDatabaseWorker implements Worker<PopulateDatabaseWorkerInput, Void> { @Nullable diff --git a/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java b/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java index 0bb56f1f9..c7c92e7b9 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java +++ b/java/com/android/dialer/simulator/impl/SimulatorVideoCall.java @@ -23,8 +23,6 @@ import android.support.annotation.Nullable; import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.TelecomManager; -import android.telecom.VideoProfile; -import android.view.ActionProvider; import android.widget.Toast; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; @@ -32,36 +30,14 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.simulator.Simulator.Event; /** Entry point in the simulator to create video calls. */ -final class SimulatorVideoCall +public final class SimulatorVideoCall implements SimulatorConnectionService.Listener, SimulatorConnection.Listener { @NonNull private final Context context; private final int initialVideoCapability; private final int initialVideoState; @Nullable private String connectionTag; - static ActionProvider getActionProvider(@NonNull Context context) { - return new SimulatorSubMenu(context) - .addItem( - "Incoming one way", - () -> - new SimulatorVideoCall(context, VideoProfile.STATE_RX_ENABLED).addNewIncomingCall()) - .addItem( - "Incoming two way", - () -> - new SimulatorVideoCall(context, VideoProfile.STATE_BIDIRECTIONAL) - .addNewIncomingCall()) - .addItem( - "Outgoing one way", - () -> - new SimulatorVideoCall(context, VideoProfile.STATE_TX_ENABLED).addNewOutgoingCall()) - .addItem( - "Outgoing two way", - () -> - new SimulatorVideoCall(context, VideoProfile.STATE_BIDIRECTIONAL) - .addNewOutgoingCall()); - } - - private SimulatorVideoCall(@NonNull Context context, int initialVideoState) { + public SimulatorVideoCall(@NonNull Context context, int initialVideoState) { this.context = Assert.isNotNull(context); this.initialVideoCapability = Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL @@ -70,7 +46,7 @@ final class SimulatorVideoCall SimulatorConnectionService.addListener(this); } - private void addNewIncomingCall() { + public void addNewIncomingCall() { if (!isVideoAccountEnabled()) { showVideoAccountSettings(); return; @@ -81,7 +57,7 @@ final class SimulatorVideoCall context, callerId, SimulatorSimCallManager.CALL_TYPE_VIDEO); } - private void addNewOutgoingCall() { + public void addNewOutgoingCall() { if (!isVideoAccountEnabled()) { showVideoAccountSettings(); return; diff --git a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java index e59cddd51..a9f332e4a 100644 --- a/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java +++ b/java/com/android/dialer/simulator/impl/SimulatorVoiceCall.java @@ -24,7 +24,6 @@ import android.support.v7.app.AppCompatActivity; import android.telecom.Connection; import android.telecom.Connection.RttModifyStatus; import android.telecom.DisconnectCause; -import android.view.ActionProvider; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutorComponent; @@ -37,58 +36,13 @@ import com.android.dialer.simulator.SimulatorComponent; import com.android.dialer.simulator.SimulatorEnrichedCall; /** Entry point in the simulator to create voice calls. */ -final class SimulatorVoiceCall +public final class SimulatorVoiceCall implements SimulatorConnectionService.Listener, SimulatorConnection.Listener { @NonNull private final Context context; @Nullable private String connectionTag; private final SimulatorEnrichedCall simulatorEnrichedCall; - static ActionProvider getActionProvider(@NonNull AppCompatActivity activity) { - return new SimulatorSubMenu(activity.getApplicationContext()) - .addItem( - "Incoming call", - () -> new SimulatorVoiceCall(activity.getApplicationContext()).addNewIncomingCall()) - .addItem( - "Outgoing call", - () -> new SimulatorVoiceCall(activity.getApplicationContext()).addNewOutgoingCall()) - .addItem( - "Customized incoming call", - () -> - new SimulatorVoiceCall(activity.getApplicationContext()) - .addNewIncomingCall(activity)) - .addItem( - "Customized outgoing call", - () -> - new SimulatorVoiceCall(activity.getApplicationContext()) - .addNewOutgoingCall(activity)) - .addItem( - "Incoming enriched call", - () -> new SimulatorVoiceCall(activity.getApplicationContext()).incomingEnrichedCall()) - .addItem( - "Outgoing enriched call", - () -> new SimulatorVoiceCall(activity.getApplicationContext()).outgoingEnrichedCall()) - .addItem( - "Spam incoming call", - () -> new SimulatorVoiceCall(activity.getApplicationContext()).addSpamIncomingCall()) - .addItem( - "Emergency call back", - () -> - new SimulatorVoiceCall(activity.getApplicationContext()).addNewEmergencyCallBack()) - .addItem( - "GSM conference", - () -> - new SimulatorConferenceCreator( - activity.getApplicationContext(), Simulator.CONFERENCE_TYPE_GSM) - .start(5)) - .addItem( - "VoLTE conference", - () -> - new SimulatorConferenceCreator( - activity.getApplicationContext(), Simulator.CONFERENCE_TYPE_VOLTE) - .start(5)); - } - - private SimulatorVoiceCall(@NonNull Context context) { + public SimulatorVoiceCall(@NonNull Context context) { this.context = Assert.isNotNull(context); simulatorEnrichedCall = SimulatorComponent.get(context).getSimulatorEnrichedCall(); SimulatorConnectionService.addListener(this); @@ -96,7 +50,7 @@ final class SimulatorVoiceCall new SimulatorConferenceCreator(context, Simulator.CONFERENCE_TYPE_GSM)); } - private void incomingEnrichedCall() { + public void incomingEnrichedCall() { simulatorEnrichedCall .setupIncomingEnrichedCall(Simulator.ENRICHED_CALL_INCOMING_NUMBER) .addListener( @@ -113,7 +67,7 @@ final class SimulatorVoiceCall DialerExecutorComponent.get(context).uiExecutor()); } - private void outgoingEnrichedCall() { + public void outgoingEnrichedCall() { getEnrichedCallManager().registerStateChangedListener(simulatorEnrichedCall); simulatorEnrichedCall .setupOutgoingEnrichedCall(Simulator.ENRICHED_CALL_OUTGOING_NUMBER) @@ -131,14 +85,14 @@ final class SimulatorVoiceCall DialerExecutorComponent.get(context).uiExecutor()); } - private void addNewIncomingCall() { + public void addNewIncomingCall() { String callerId = "+44 (0) 20 7031 3000" /* Google London office */; connectionTag = SimulatorSimCallManager.addNewIncomingCall( context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE); } - private void addNewIncomingCall(AppCompatActivity activity) { + public void addNewIncomingCall(AppCompatActivity activity) { SimulatorDialogFragment.newInstance( (callerId, callerIdPresentation) -> { Bundle extras = new Bundle(); @@ -150,14 +104,14 @@ final class SimulatorVoiceCall .show(activity.getSupportFragmentManager(), "SimulatorDialog"); } - private void addNewOutgoingCall() { + public void addNewOutgoingCall() { String callerId = "+55-31-2128-6800"; // Brazil office. connectionTag = SimulatorSimCallManager.addNewOutgoingCall( context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE); } - private void addNewOutgoingCall(AppCompatActivity activity) { + public void addNewOutgoingCall(AppCompatActivity activity) { SimulatorDialogFragment.newInstance( (callerId, callerIdPresentation) -> { Bundle extras = new Bundle(); @@ -169,14 +123,14 @@ final class SimulatorVoiceCall .show(activity.getSupportFragmentManager(), "SimulatorDialog"); } - private void addSpamIncomingCall() { + public void addSpamIncomingCall() { String callerId = "+1-661-778-3020"; /* Blacklisted custom spam number */ connectionTag = SimulatorSimCallManager.addNewIncomingCall( context, callerId, SimulatorSimCallManager.CALL_TYPE_VOICE); } - private void addNewEmergencyCallBack() { + public void addNewEmergencyCallBack() { String callerId = "911"; connectionTag = SimulatorSimCallManager.addNewIncomingCall( diff --git a/java/com/android/dialer/simulator/portal/SimulatorMainPortal.java b/java/com/android/dialer/simulator/portal/SimulatorMainPortal.java new file mode 100644 index 000000000..fdec2a540 --- /dev/null +++ b/java/com/android/dialer/simulator/portal/SimulatorMainPortal.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2018 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.simulator.portal; + +import android.content.Context; +import android.support.v7.app.AppCompatActivity; +import android.telecom.VideoProfile; +import android.view.ActionProvider; +import com.android.dialer.enrichedcall.simulator.EnrichedCallSimulatorActivity; +import com.android.dialer.simulator.Simulator; +import com.android.dialer.simulator.SimulatorComponent; +import com.android.dialer.simulator.impl.SimulatorConferenceCreator; +import com.android.dialer.simulator.impl.SimulatorMissedCallCreator; +import com.android.dialer.simulator.impl.SimulatorRttCall; +import com.android.dialer.simulator.impl.SimulatorSimCallManager; +import com.android.dialer.simulator.impl.SimulatorUtils; +import com.android.dialer.simulator.impl.SimulatorVideoCall; +import com.android.dialer.simulator.impl.SimulatorVoiceCall; +import com.google.common.collect.ImmutableMap; + +/** Implements the top level simulator menu. */ +public final class SimulatorMainPortal { + + private final Context context; + private final AppCompatActivity activity; + private SimulatorPortalEntryGroup simulatorMainPortal; + + public SimulatorMainPortal(AppCompatActivity activity) { + this.activity = activity; + this.context = activity.getApplicationContext(); + buildMainPortal(); + } + + private void buildMainPortal() { + this.simulatorMainPortal = + SimulatorPortalEntryGroup.builder() + .setMethods( + ImmutableMap.<String, Runnable>builder() + .put("Populate database", () -> SimulatorUtils.populateDatabase(context)) + .put("Populate voicemail", () -> SimulatorUtils.populateVoicemail(context)) + .put( + "Fast Populate database", + () -> SimulatorUtils.fastPopulateDatabase(context)) + .put( + "Fast populate voicemail database", + () -> SimulatorUtils.populateVoicemailFast(context)) + .put("Clean database", () -> SimulatorUtils.cleanDatabase(context)) + .put("clear preferred SIM", () -> SimulatorUtils.clearPreferredSim(context)) + .put("Sync voicemail", () -> SimulatorUtils.syncVoicemail(context)) + .put("Share persistent log", () -> SimulatorUtils.sharePersistentLog(context)) + .put( + "Enriched call simulator", + () -> + context.startActivity(EnrichedCallSimulatorActivity.newIntent(context))) + .put( + "Enable simulator mode", + () -> { + SimulatorComponent.get(context).getSimulator().enableSimulatorMode(); + SimulatorSimCallManager.register(context); + }) + .put( + "Disable simulator mode", + () -> { + SimulatorComponent.get(context).getSimulator().disableSimulatorMode(); + SimulatorSimCallManager.unregister(context); + }) + .build()) + .setSubPortals( + ImmutableMap.of( + "VoiceCall", + buildSimulatorVoiceCallPortal(), + "VideoCall", + buildSimulatorVideoCallPortal(), + "RttCall", + buildSimulatorRttCallPortal(), + "Notifications", + buildSimulatorNotificationsPortal())) + .build(); + } + + public SimulatorPortalEntryGroup buildSimulatorVoiceCallPortal() { + return SimulatorPortalEntryGroup.builder() + .setMethods( + ImmutableMap.<String, Runnable>builder() + .put("Incoming call", () -> new SimulatorVoiceCall(context).addNewIncomingCall()) + .put("Outgoing call", () -> new SimulatorVoiceCall(context).addNewOutgoingCall()) + .put( + "Customized incoming call", + () -> new SimulatorVoiceCall(context).addNewIncomingCall(activity)) + .put( + "Customized outgoing call", + () -> new SimulatorVoiceCall(context).addNewOutgoingCall(activity)) + .put( + "Incoming enriched call", + () -> new SimulatorVoiceCall(context).incomingEnrichedCall()) + .put( + "Outgoing enriched call", + () -> new SimulatorVoiceCall(context).outgoingEnrichedCall()) + .put( + "Spam incoming call", + () -> new SimulatorVoiceCall(context).addSpamIncomingCall()) + .put( + "Emergency call back", + () -> new SimulatorVoiceCall(context).addNewEmergencyCallBack()) + .put( + "GSM conference", + () -> + new SimulatorConferenceCreator(context, Simulator.CONFERENCE_TYPE_GSM) + .start(5)) + .put( + "VoLTE conference", + () -> + new SimulatorConferenceCreator(context, Simulator.CONFERENCE_TYPE_VOLTE) + .start(5)) + .build()) + .build(); + } + + private SimulatorPortalEntryGroup buildSimulatorVideoCallPortal() { + return SimulatorPortalEntryGroup.builder() + .setMethods( + ImmutableMap.<String, Runnable>builder() + .put( + "Incoming one way", + () -> + new SimulatorVideoCall(context, VideoProfile.STATE_RX_ENABLED) + .addNewIncomingCall()) + .put( + "Incoming two way", + () -> + new SimulatorVideoCall(context, VideoProfile.STATE_BIDIRECTIONAL) + .addNewIncomingCall()) + .put( + "Outgoing one way", + () -> + new SimulatorVideoCall(context, VideoProfile.STATE_TX_ENABLED) + .addNewOutgoingCall()) + .put( + "Outgoing two way", + () -> + new SimulatorVideoCall(context, VideoProfile.STATE_BIDIRECTIONAL) + .addNewOutgoingCall()) + .build()) + .build(); + } + + private SimulatorPortalEntryGroup buildSimulatorRttCallPortal() { + return SimulatorPortalEntryGroup.builder() + .setMethods( + ImmutableMap.<String, Runnable>builder() + .put("Incoming call", () -> new SimulatorRttCall(context).addNewIncomingCall(false)) + .put("Outgoing call", () -> new SimulatorRttCall(context).addNewOutgoingCall()) + .put("Emergency call", () -> new SimulatorRttCall(context).addNewEmergencyCall()) + .build()) + .build(); + } + + private SimulatorPortalEntryGroup buildSimulatorNotificationsPortal() { + return SimulatorPortalEntryGroup.builder() + .setMethods( + ImmutableMap.<String, Runnable>builder() + .put( + "Missed calls", + () -> + new SimulatorMissedCallCreator(context) + .start(SimulatorUtils.NOTIFICATION_COUNT)) + .put( + "Missed calls (few)", + () -> + new SimulatorMissedCallCreator(context) + .start(SimulatorUtils.NOTIFICATION_COUNT_FEW)) + .put( + "Voicemails", + () -> + SimulatorUtils.addVoicemailNotifications( + context, SimulatorUtils.NOTIFICATION_COUNT)) + .build()) + .build(); + } + + public ActionProvider getActionProvider() { + return new SimulatorMenu(context, simulatorMainPortal); + } +} diff --git a/java/com/android/dialer/simulator/portal/SimulatorMenu.java b/java/com/android/dialer/simulator/portal/SimulatorMenu.java new file mode 100644 index 000000000..01fd4aa0e --- /dev/null +++ b/java/com/android/dialer/simulator/portal/SimulatorMenu.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 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.simulator.portal; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.view.ActionProvider; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import com.android.dialer.common.Assert; +import java.util.Map.Entry; + +/** Makes option menu for simulator. */ +public final class SimulatorMenu extends ActionProvider { + + SimulatorPortalEntryGroup portal; + + Context context; + + public SimulatorMenu(@NonNull Context context, SimulatorPortalEntryGroup portal) { + super(Assert.isNotNull(context)); + this.context = context; + this.portal = portal; + } + + @Override + public View onCreateActionView() { + return null; + } + + @Override + public View onCreateActionView(MenuItem forItem) { + return null; + } + + @Override + public boolean hasSubMenu() { + return true; + } + + @Override + public void onPrepareSubMenu(SubMenu subMenu) { + super.onPrepareSubMenu(subMenu); + subMenu.clear(); + + for (Entry<String, SimulatorPortalEntryGroup> subPortal : portal.subPortals().entrySet()) { + subMenu + .add(subPortal.getKey()) + .setActionProvider(new SimulatorMenu(context, subPortal.getValue())); + } + for (Entry<String, Runnable> method : portal.methods().entrySet()) { + subMenu + .add(method.getKey()) + .setOnMenuItemClickListener( + (i) -> { + method.getValue().run(); + return true; + }); + } + } +} diff --git a/java/com/android/dialer/simulator/portal/SimulatorPortalEntryGroup.java b/java/com/android/dialer/simulator/portal/SimulatorPortalEntryGroup.java new file mode 100644 index 000000000..30a248cb1 --- /dev/null +++ b/java/com/android/dialer/simulator/portal/SimulatorPortalEntryGroup.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 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.simulator.portal; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.Map; + +/** Represents a portal that receives requests from either UI or IPC. */ +@AutoValue +public abstract class SimulatorPortalEntryGroup { + abstract ImmutableMap<String, Runnable> methods(); + + abstract ImmutableMap<String, SimulatorPortalEntryGroup> subPortals(); + + static Builder builder() { + return new AutoValue_SimulatorPortalEntryGroup.Builder() + .setMethods(Collections.emptyMap()) + .setSubPortals(Collections.emptyMap()); + } + + @AutoValue.Builder + abstract static class Builder { + abstract Builder setMethods(Map<String, Runnable> value); + + abstract Builder setSubPortals(Map<String, SimulatorPortalEntryGroup> value); + + abstract SimulatorPortalEntryGroup build(); + } +} diff --git a/java/com/android/dialer/spam/Spam.java b/java/com/android/dialer/spam/Spam.java index 181a55dea..0229782bf 100644 --- a/java/com/android/dialer/spam/Spam.java +++ b/java/com/android/dialer/spam/Spam.java @@ -18,7 +18,6 @@ package com.android.dialer.spam; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.android.dialer.DialerPhoneNumber; import com.android.dialer.logging.ContactLookupResult; @@ -75,30 +74,6 @@ public interface Spam { ListenableFuture<Void> updateSpamListDownload(boolean isEnabledByUser); /** - * @param number The number to check if the number is in the user's white list (non spam list) - * @param countryIso The country ISO of the call. - * @param listener The callback to be invoked after {@code Info} is fetched. - */ - void checkUserMarkedNonSpamStatus( - String number, @Nullable String countryIso, @NonNull Listener listener); - - /** - * @param number The number to check if it is in user's spam list - * @param countryIso The country ISO of the call. - * @param listener The callback to be invoked after {@code Info} is fetched. - */ - void checkUserMarkedSpamStatus( - String number, @Nullable String countryIso, @NonNull Listener listener); - - /** - * @param number The number to check if it is in the global spam list - * @param countryIso The country ISO of the call. - * @param listener The callback to be invoked after {@code Info} is fetched. - */ - void checkGlobalSpamListStatus( - String number, @Nullable String countryIso, @NonNull Listener listener); - - /** * Synchronously checks if the given number is suspected of being a spamer. * * @param number The phone number of the call. @@ -191,11 +166,4 @@ public interface Spam { int callType, ReportingLocation.Type from, ContactSource.Type contactSourceType); - - /** Callback to be invoked when data is fetched. */ - interface Listener { - - /** Called when data is fetched. */ - void onComplete(boolean isSpam); - } } diff --git a/java/com/android/dialer/spam/status/SimpleSpamStatus.java b/java/com/android/dialer/spam/status/SimpleSpamStatus.java index ff080ed1d..5f45c1a4f 100644 --- a/java/com/android/dialer/spam/status/SimpleSpamStatus.java +++ b/java/com/android/dialer/spam/status/SimpleSpamStatus.java @@ -26,7 +26,11 @@ public abstract class SimpleSpamStatus implements SpamStatus { /** Returns a SimpleSpamStatus with the given boolean and timestamp. */ public static SimpleSpamStatus create(boolean isSpam, @Nullable Long timestampMillis) { - return new AutoValue_SimpleSpamStatus(isSpam, Optional.fromNullable(timestampMillis)); + return builder() + .setSpam(isSpam) + .setTimestampMillis(timestampMillis) + .setSpamMetadata(SpamMetadata.empty()) + .build(); } /** Returns a SimpleSpamStatus that's not marked as spam and has no timestamp. */ @@ -34,9 +38,23 @@ public abstract class SimpleSpamStatus implements SpamStatus { return create(false, null); } - /** Returns an empty {@link SpamMetadata}. */ - @Override - public final SpamMetadata getSpamMetadata() { - return SpamMetadata.empty(); + public static Builder builder() { + return new AutoValue_SimpleSpamStatus.Builder(); + } + + /** Creates instances of SimpleSpamStatus. */ + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder setSpam(boolean isSpam); + + abstract Builder setTimestampMillis(Optional<Long> timestamp); + + public Builder setTimestampMillis(@Nullable Long timestampMillis) { + return setTimestampMillis(Optional.fromNullable(timestampMillis)); + } + + public abstract Builder setSpamMetadata(SpamMetadata spamMetadata); + + public abstract SimpleSpamStatus build(); } } diff --git a/java/com/android/dialer/spam/SpamSettingsStub.java b/java/com/android/dialer/spam/stub/SpamSettingsStub.java index 905daa45c..194d18451 100644 --- a/java/com/android/dialer/spam/SpamSettingsStub.java +++ b/java/com/android/dialer/spam/stub/SpamSettingsStub.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.android.dialer.spam; +package com.android.dialer.spam.stub; import android.content.Context; import android.content.Intent; +import com.android.dialer.spam.SpamSettings; import javax.inject.Inject; /** Default implementation of SpamSettings. */ diff --git a/java/com/android/dialer/spam/SpamStub.java b/java/com/android/dialer/spam/stub/SpamStub.java index 2789c01e7..5eeed4571 100644 --- a/java/com/android/dialer/spam/SpamStub.java +++ b/java/com/android/dialer/spam/stub/SpamStub.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.dialer.spam; +package com.android.dialer.spam.stub; import android.support.annotation.Nullable; import com.android.dialer.DialerPhoneNumber; @@ -22,6 +22,7 @@ import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor; import com.android.dialer.logging.ContactLookupResult; import com.android.dialer.logging.ContactSource; import com.android.dialer.logging.ReportingLocation; +import com.android.dialer.spam.Spam; import com.android.dialer.spam.status.SimpleSpamStatus; import com.android.dialer.spam.status.SpamStatus; import com.google.common.collect.ImmutableMap; @@ -73,21 +74,6 @@ public class SpamStub implements Spam { } @Override - public void checkUserMarkedNonSpamStatus(String number, String countryIso, Listener listener) { - listener.onComplete(false); - } - - @Override - public void checkUserMarkedSpamStatus(String number, String countryIso, Listener listener) { - listener.onComplete(false); - } - - @Override - public void checkGlobalSpamListStatus(String number, String countryIso, Listener listener) { - listener.onComplete(false); - } - - @Override public boolean checkSpamStatusSynchronous(String number, String countryIso) { return false; } diff --git a/java/com/android/dialer/spam/StubSpamModule.java b/java/com/android/dialer/spam/stub/StubSpamModule.java index b60967475..e6b4622df 100644 --- a/java/com/android/dialer/spam/StubSpamModule.java +++ b/java/com/android/dialer/spam/stub/StubSpamModule.java @@ -14,10 +14,12 @@ * limitations under the License. */ -package com.android.dialer.spam; +package com.android.dialer.spam.stub; import com.android.dialer.inject.DialerVariant; import com.android.dialer.inject.InstallIn; +import com.android.dialer.spam.Spam; +import com.android.dialer.spam.SpamSettings; import dagger.Binds; import dagger.Module; diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java index fac9a13d2..d9593c211 100644 --- a/java/com/android/dialer/speeddial/SpeedDialFragment.java +++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java @@ -16,12 +16,16 @@ package com.android.dialer.speeddial; +import android.Manifest; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; @@ -35,6 +39,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.common.Assert; import com.android.dialer.common.FragmentUtils; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DefaultFutureCallback; @@ -59,9 +64,13 @@ import com.android.dialer.speeddial.draghelper.SpeedDialLayoutManager; import com.android.dialer.speeddial.loader.SpeedDialUiItem; import com.android.dialer.speeddial.loader.UiItemLoaderComponent; import com.android.dialer.util.IntentUtil; +import com.android.dialer.util.PermissionsUtil; +import com.android.dialer.widget.EmptyContentView; +import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -76,6 +85,20 @@ import java.util.List; */ public class SpeedDialFragment extends Fragment { + private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1; + + /** + * Listen to broadcast events about permissions in order to be notified if the READ_CONTACTS + * permission is granted via the UI in another fragment. + */ + private final BroadcastReceiver readContactsPermissionGrantedReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + loadContacts(); + } + }; + private final SpeedDialHeaderListener headerListener = new SpeedDialFragmentHeaderListener(); private final SpeedDialSuggestedListener suggestedListener = new SpeedDialSuggestedListener(); @@ -83,6 +106,8 @@ public class SpeedDialFragment extends Fragment { private SupportUiListener<ImmutableList<SpeedDialUiItem>> speedDialLoaderListener; private SpeedDialFavoritesListener favoritesListener; + private EmptyContentView emptyContentView; + /** * We update the UI every time the fragment is resumed. This boolean suppresses that functionality * once per onResume call. @@ -99,6 +124,12 @@ public class SpeedDialFragment extends Fragment { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LogUtil.enterBlock("SpeedDialFragment.onCreateView"); View rootLayout = inflater.inflate(R.layout.fragment_speed_dial, container, false); + emptyContentView = rootLayout.findViewById(R.id.speed_dial_empty_content_view); + emptyContentView.setActionLabel(R.string.speed_dial_turn_on_contacts_permission); + emptyContentView.setDescription(R.string.speed_dial_contacts_permission_description); + emptyContentView.setImage(R.drawable.empty_speed_dial); + emptyContentView.setActionClickedListener( + new SpeedDialEmptyContentViewClickedListener(getContext(), this)); speedDialLoaderListener = DialerExecutorComponent.get(getContext()) @@ -132,11 +163,69 @@ public class SpeedDialFragment extends Fragment { @Override public void onResume() { super.onResume(); + loadContacts(); + } + + @Override + public void onPause() { + super.onPause(); + favoritesListener.hideMenu(); + suggestedListener.onPause(); + } + + @Override + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + if (hidden) { + onHidden(); + } else { + loadContacts(); + } + } + + private void onHidden() { + if (!PermissionsUtil.hasContactsReadPermissions(getContext())) { + return; + } + + Futures.addCallback( + DialerExecutorComponent.get(getContext()) + .backgroundExecutor() + .submit( + () -> { + UiItemLoaderComponent.get(getContext()) + .speedDialUiItemMutator() + .updatePinnedPosition(adapter.getSpeedDialUiItems()); + return null; + }), + new DefaultFutureCallback<>(), + DialerExecutorComponent.get(getContext()).backgroundExecutor()); + } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE + && grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + PermissionsUtil.notifyPermissionGranted(getContext(), Manifest.permission.READ_CONTACTS); + loadContacts(); + } + } + + private void loadContacts() { if (!updateSpeedDialItemsOnResume) { updateSpeedDialItemsOnResume = true; return; } + if (!PermissionsUtil.hasContactsReadPermissions(getContext())) { + emptyContentView.setVisibility(View.VISIBLE); + return; + } else { + emptyContentView.setVisibility(View.GONE); + } + speedDialLoaderListener.listen( getContext(), UiItemLoaderComponent.get(getContext()).speedDialUiItemMutator().loadSpeedDialUiItems(), @@ -179,22 +268,17 @@ public class SpeedDialFragment extends Fragment { } @Override - public void onPause() { - super.onPause(); - favoritesListener.hideMenu(); - Futures.addCallback( - DialerExecutorComponent.get(getContext()) - .backgroundExecutor() - .submit( - () -> { - UiItemLoaderComponent.get(getContext()) - .speedDialUiItemMutator() - .updatePinnedPosition(adapter.getSpeedDialUiItems()); - return null; - }), - new DefaultFutureCallback<>(), - DialerExecutorComponent.get(getContext()).backgroundExecutor()); - suggestedListener.onPause(); + public void onStart() { + super.onStart(); + PermissionsUtil.registerPermissionReceiver( + getActivity(), readContactsPermissionGrantedReceiver, Manifest.permission.READ_CONTACTS); + } + + @Override + public void onStop() { + super.onStop(); + PermissionsUtil.unregisterPermissionReceiver( + getContext(), readContactsPermissionGrantedReceiver); } private class SpeedDialFragmentHeaderListener implements SpeedDialHeaderListener { @@ -455,6 +539,30 @@ public class SpeedDialFragment extends Fragment { } } + private static final class SpeedDialEmptyContentViewClickedListener + implements OnEmptyViewActionButtonClickedListener { + + private final Context context; + private final Fragment fragment; + + private SpeedDialEmptyContentViewClickedListener(Context context, Fragment fragment) { + this.context = context; + this.fragment = fragment; + } + + @Override + public void onEmptyViewActionButtonClicked() { + String[] deniedPermissions = + PermissionsUtil.getPermissionsCurrentlyDenied( + context, PermissionsUtil.allContactsGroupPermissionsUsedInDialer); + Assert.checkArgument(deniedPermissions.length > 0); + LogUtil.i( + "OldSpeedDialFragment.onEmptyViewActionButtonClicked", + "Requesting permissions: " + Arrays.toString(deniedPermissions)); + fragment.requestPermissions(deniedPermissions, READ_CONTACTS_PERMISSION_REQUEST_CODE); + } + } + /** Listener for when a SpeedDialUiItem is updated. */ private class UpdateSpeedDialAdapterListener { diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java index 1416a203d..211af86ad 100644 --- a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java +++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java @@ -125,7 +125,7 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper Channel.builder() .setNumber(number) .setPhoneType(cursor.getInt(POSITION_PHONE_TYPE)) - .setLabel(cursor.getString(POSITION_PHONE_LABEL)) + .setLabel(Optional.of(cursor.getString(POSITION_PHONE_LABEL)).or("")) .setTechnology(cursor.getInt(POSITION_PHONE_TECHNOLOGY)) .build(); } diff --git a/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml b/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml index 9a42377be..1e35091c9 100644 --- a/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml +++ b/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml @@ -26,5 +26,12 @@ android:clipToPadding="false" android:background="@color/background_dialer_light" android:paddingBottom="@dimen/floating_action_button_list_bottom_padding"/> + + <com.android.dialer.widget.EmptyContentView + android:id="@+id/speed_dial_empty_content_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone"/> </FrameLayout> diff --git a/java/com/android/dialer/speeddial/res/values/strings.xml b/java/com/android/dialer/speeddial/res/values/strings.xml index 0053074b2..7f11119c7 100644 --- a/java/com/android/dialer/speeddial/res/values/strings.xml +++ b/java/com/android/dialer/speeddial/res/values/strings.xml @@ -59,4 +59,10 @@ <!-- Text shown to the user in a button to prompt them to mark a contact as a favorite contact [CHAR LIMIT=30]. --> <string name="suggested_contact_bottom_sheet_add_favorite_option">Add favorite</string> + + <!-- Shown as a prompt to turn on the contacts permission to enable speed dial [CHAR LIMIT=NONE]--> + <string name="speed_dial_contacts_permission_description">To enable speed dial, turn on the Contacts permission.</string> + + <!-- The label of the button used to turn on a single permission [CHAR LIMIT=30]--> + <string name="speed_dial_turn_on_contacts_permission">Turn on</string> </resources>
\ No newline at end of file diff --git a/java/com/android/dialer/theme/res/drawable-hdpi/empty_speed_dial.png b/java/com/android/dialer/theme/res/drawable-hdpi/empty_speed_dial.png Binary files differnew file mode 100644 index 000000000..5a1829599 --- /dev/null +++ b/java/com/android/dialer/theme/res/drawable-hdpi/empty_speed_dial.png diff --git a/java/com/android/dialer/theme/res/drawable-mdpi/empty_speed_dial.png b/java/com/android/dialer/theme/res/drawable-mdpi/empty_speed_dial.png Binary files differnew file mode 100644 index 000000000..3c95eeb33 --- /dev/null +++ b/java/com/android/dialer/theme/res/drawable-mdpi/empty_speed_dial.png diff --git a/java/com/android/dialer/theme/res/drawable-xhdpi/empty_speed_dial.png b/java/com/android/dialer/theme/res/drawable-xhdpi/empty_speed_dial.png Binary files differnew file mode 100644 index 000000000..9335011fe --- /dev/null +++ b/java/com/android/dialer/theme/res/drawable-xhdpi/empty_speed_dial.png diff --git a/java/com/android/dialer/theme/res/drawable-xxhdpi/empty_speed_dial.png b/java/com/android/dialer/theme/res/drawable-xxhdpi/empty_speed_dial.png Binary files differnew file mode 100644 index 000000000..04ab7b4dc --- /dev/null +++ b/java/com/android/dialer/theme/res/drawable-xxhdpi/empty_speed_dial.png diff --git a/java/com/android/dialer/widget/res/drawable-hdpi/empty_contacts.png b/java/com/android/dialer/widget/res/drawable-hdpi/empty_contacts.png Binary files differindex d3c0378f5..628f301b2 100644 --- a/java/com/android/dialer/widget/res/drawable-hdpi/empty_contacts.png +++ b/java/com/android/dialer/widget/res/drawable-hdpi/empty_contacts.png diff --git a/java/com/android/dialer/widget/res/drawable-mdpi/empty_contacts.png b/java/com/android/dialer/widget/res/drawable-mdpi/empty_contacts.png Binary files differindex 2ce7eae37..bb2a13340 100644 --- a/java/com/android/dialer/widget/res/drawable-mdpi/empty_contacts.png +++ b/java/com/android/dialer/widget/res/drawable-mdpi/empty_contacts.png diff --git a/java/com/android/dialer/widget/res/drawable-xhdpi/empty_contacts.png b/java/com/android/dialer/widget/res/drawable-xhdpi/empty_contacts.png Binary files differindex 65b1de333..5edeab210 100644 --- a/java/com/android/dialer/widget/res/drawable-xhdpi/empty_contacts.png +++ b/java/com/android/dialer/widget/res/drawable-xhdpi/empty_contacts.png diff --git a/java/com/android/dialer/widget/res/drawable-xxhdpi/empty_contacts.png b/java/com/android/dialer/widget/res/drawable-xxhdpi/empty_contacts.png Binary files differindex 407d78c9c..7d6c05963 100644 --- a/java/com/android/dialer/widget/res/drawable-xxhdpi/empty_contacts.png +++ b/java/com/android/dialer/widget/res/drawable-xxhdpi/empty_contacts.png diff --git a/java/com/android/dialer/widget/res/drawable-xxxhdpi/empty_contacts.png b/java/com/android/dialer/widget/res/drawable-xxxhdpi/empty_contacts.png Binary files differindex 5893965e9..ad44d2452 100644 --- a/java/com/android/dialer/widget/res/drawable-xxxhdpi/empty_contacts.png +++ b/java/com/android/dialer/widget/res/drawable-xxxhdpi/empty_contacts.png diff --git a/java/com/android/incallui/CallButtonPresenter.java b/java/com/android/incallui/CallButtonPresenter.java index 3fd3ee64b..a8b060daa 100644 --- a/java/com/android/incallui/CallButtonPresenter.java +++ b/java/com/android/incallui/CallButtonPresenter.java @@ -62,13 +62,14 @@ public class CallButtonPresenter Listener, InCallButtonUiDelegate { - private static final String KEY_AUTOMATICALLY_MUTED = "incall_key_automatically_muted"; + private static final String KEY_AUTOMATICALLY_MUTED_BY_ADD_CALL = + "incall_key_automatically_muted_by_add_call"; private static final String KEY_PREVIOUS_MUTE_STATE = "incall_key_previous_mute_state"; private final Context context; private InCallButtonUi inCallButtonUi; private DialerCall call; - private boolean automaticallyMuted = false; + private boolean automaticallyMutedByAddCall = false; private boolean previousMuteState = false; private boolean isInCallButtonUiReady; private PhoneAccountHandle otherAccount; @@ -276,8 +277,14 @@ public class CallButtonPresenter DialerImpression.Type.IN_CALL_ADD_CALL_BUTTON_PRESSED, call.getUniqueCallId(), call.getTimeAddedMs()); + if (automaticallyMutedByAddCall) { + // Since clicking add call button brings user to MainActivity and coming back refreshes mute + // state, add call button should only be clicked once during InCallActivity shows. Otherwise, + // we set previousMuteState wrong. + return; + } // Automatically mute the current call - automaticallyMuted = true; + automaticallyMutedByAddCall = true; previousMuteState = AudioModeProvider.getInstance().getAudioState().isMuted(); // Simulate a click on the mute button muteClicked(true /* checked */, false /* clickedByUser */); @@ -540,25 +547,27 @@ public class CallButtonPresenter @Override public void refreshMuteState() { // Restore the previous mute state - if (automaticallyMuted + if (automaticallyMutedByAddCall && AudioModeProvider.getInstance().getAudioState().isMuted() != previousMuteState) { if (inCallButtonUi == null) { return; } muteClicked(previousMuteState, false /* clickedByUser */); } - automaticallyMuted = false; + automaticallyMutedByAddCall = false; } @Override public void onSaveInstanceState(Bundle outState) { - outState.putBoolean(KEY_AUTOMATICALLY_MUTED, automaticallyMuted); + outState.putBoolean(KEY_AUTOMATICALLY_MUTED_BY_ADD_CALL, automaticallyMutedByAddCall); outState.putBoolean(KEY_PREVIOUS_MUTE_STATE, previousMuteState); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { - automaticallyMuted = savedInstanceState.getBoolean(KEY_AUTOMATICALLY_MUTED, automaticallyMuted); + automaticallyMutedByAddCall = + savedInstanceState.getBoolean( + KEY_AUTOMATICALLY_MUTED_BY_ADD_CALL, automaticallyMutedByAddCall); previousMuteState = savedInstanceState.getBoolean(KEY_PREVIOUS_MUTE_STATE, previousMuteState); } diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java index fb1de05bd..d44a5daa2 100644 --- a/java/com/android/incallui/answer/impl/AnswerFragment.java +++ b/java/com/android/incallui/answer/impl/AnswerFragment.java @@ -82,9 +82,11 @@ import com.android.incallui.incalluilock.InCallUiLock; import com.android.incallui.maps.MapsComponent; import com.android.incallui.sessiondata.AvatarPresenter; import com.android.incallui.sessiondata.MultimediaFragment; +import com.android.incallui.speakeasy.SpeakEasyComponent; import com.android.incallui.util.AccessibilityUtil; import com.android.incallui.video.protocol.VideoCallScreen; import com.android.incallui.videotech.utils.VideoUtils; +import com.google.common.base.Optional; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -206,7 +208,7 @@ public class AnswerFragment extends Fragment } }; - @DrawableRes public final int icon; + @DrawableRes public int icon; @StringRes public final int contentDescription; @StringRes public final int accessibilityLabel; @StringRes public final int hintText; @@ -456,6 +458,11 @@ public class AnswerFragment extends Fragment answerAndReleaseButton.setVisibility(View.VISIBLE); answerScreenDelegate.onAnswerAndReleaseButtonEnabled(); } else if (allowSpeakEasy()) { + Optional<Integer> alternativeIcon = SpeakEasyComponent.get(getContext()).speakEasyIcon(); + if (alternativeIcon.isPresent()) { + // TODO(erfanian): Replace enum hack when we have a dedicated button. + SecondaryBehavior.SPEAKEASY.icon = alternativeIcon.get(); + } answerAndReleaseBehavior = SecondaryBehavior.SPEAKEASY; answerAndReleaseBehavior.applyToView(answerAndReleaseButton); answerAndReleaseButton.setVisibility(View.VISIBLE); diff --git a/java/com/android/incallui/call/CallList.java b/java/com/android/incallui/call/CallList.java index 13be252dd..6940f7d6c 100644 --- a/java/com/android/incallui/call/CallList.java +++ b/java/com/android/incallui/call/CallList.java @@ -23,13 +23,11 @@ import android.os.Trace; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; -import android.support.v4.os.BuildCompat; import android.telecom.Call; import android.telecom.DisconnectCause; import android.telecom.PhoneAccount; import android.util.ArrayMap; import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; -import com.android.dialer.blocking.FilteredNumbersUtil; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutorComponent; @@ -41,7 +39,6 @@ import com.android.dialer.metrics.Metrics; import com.android.dialer.metrics.MetricsComponent; import com.android.dialer.promotion.RttPromotion; import com.android.dialer.shortcuts.ShortcutUsageReporter; -import com.android.dialer.spam.Spam; import com.android.dialer.spam.SpamComponent; import com.android.dialer.spam.status.SpamStatus; import com.android.dialer.telecom.TelecomCallUtil; @@ -164,20 +161,7 @@ public class CallList implements DialerCallDelegate { call.getState() == DialerCallState.INCOMING || call.getState() == DialerCallState.CALL_WAITING; boolean isSpam = result.isSpam(); - if (isSpam) { - if (!isIncomingCall) { - LogUtil.i( - "CallList.onCallAdded", - "marking spam call as not spam because it's not an incoming call"); - isSpam = false; - } else if (isPotentialEmergencyCallback(context, call)) { - LogUtil.i( - "CallList.onCallAdded", - "marking spam call as not spam because an emergency call was made on this" - + " device recently"); - isSpam = false; - } - } + call.setSpamStatus(result); if (isIncomingCall) { Logger.get(context) @@ -188,7 +172,6 @@ public class CallList implements DialerCallDelegate { call.getUniqueCallId(), call.getTimeAddedMs()); } - call.setSpam(isSpam); onUpdateCall(call); notifyGenericListeners(); } @@ -201,7 +184,6 @@ public class CallList implements DialerCallDelegate { DialerExecutorComponent.get(context).uiExecutor()); Trace.beginSection("updateUserMarkedSpamStatus"); - updateUserMarkedSpamStatus(call, context, number); Trace.endSection(); } Trace.endSection(); @@ -279,60 +261,11 @@ public class CallList implements DialerCallDelegate { impression, incomingCall.getUniqueCallId(), incomingCall.getTimeAddedMs()); } - private static boolean isPotentialEmergencyCallback(Context context, DialerCall call) { - if (BuildCompat.isAtLeastO()) { - return call.isPotentialEmergencyCallback(); - } else { - long timestampMillis = FilteredNumbersUtil.getLastEmergencyCallTimeMillis(context); - return call.isInEmergencyCallbackWindow(timestampMillis); - } - } - @Override public DialerCall getDialerCallFromTelecomCall(Call telecomCall) { return callByTelecomCall.get(telecomCall); } - private void updateUserMarkedSpamStatus( - final DialerCall call, final Context context, String number) { - - SpamComponent.get(context) - .spam() - .checkUserMarkedNonSpamStatus( - number, - call.getCountryIso(), - new Spam.Listener() { - @Override - public void onComplete(boolean isInUserWhiteList) { - call.setIsInUserWhiteList(isInUserWhiteList); - } - }); - - SpamComponent.get(context) - .spam() - .checkGlobalSpamListStatus( - number, - call.getCountryIso(), - new Spam.Listener() { - @Override - public void onComplete(boolean isInGlobalSpamList) { - call.setIsInGlobalSpamList(isInGlobalSpamList); - } - }); - - SpamComponent.get(context) - .spam() - .checkUserMarkedSpamStatus( - number, - call.getCountryIso(), - new Spam.Listener() { - @Override - public void onComplete(boolean isInUserSpamList) { - call.setIsInUserSpamList(isInUserSpamList); - } - }); - } - public void onCallRemoved(Context context, android.telecom.Call telecomCall) { if (callByTelecomCall.containsKey(telecomCall)) { DialerCall call = callByTelecomCall.get(telecomCall); diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index 431634a0c..da7c54d27 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -52,6 +52,7 @@ import android.widget.Toast; import com.android.contacts.common.compat.CallCompat; import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.assisteddialing.TransformationInfo; +import com.android.dialer.blocking.FilteredNumbersUtil; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentParser; import com.android.dialer.callintent.CallSpecificAppData; @@ -76,6 +77,7 @@ import com.android.dialer.logging.Logger; import com.android.dialer.preferredsim.PreferredAccountRecorder; import com.android.dialer.rtt.RttTranscript; import com.android.dialer.rtt.RttTranscriptUtil; +import com.android.dialer.spam.status.SpamStatus; import com.android.dialer.telecom.TelecomCallUtil; import com.android.dialer.telecom.TelecomUtil; import com.android.dialer.theme.R; @@ -91,6 +93,7 @@ import com.android.incallui.videotech.duo.DuoVideoTech; import com.android.incallui.videotech.empty.EmptyVideoTech; import com.android.incallui.videotech.ims.ImsVideoTech; import com.android.incallui.videotech.utils.VideoUtils; +import com.google.common.base.Optional; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import java.io.IOException; @@ -165,14 +168,10 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa private String callSubject; @Nullable private PhoneAccountHandle phoneAccountHandle; @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN; - private boolean isSpam; - private boolean isBlocked; - - @Nullable private Boolean isInUserSpamList; - @Nullable private Boolean isInUserWhiteList; + @Nullable private SpamStatus spamStatus; + private boolean isBlocked; - @Nullable private Boolean isInGlobalSpamList; private boolean didShowCameraPermission; private boolean didDismissVideoChargesAlertDialog; private PersistableBundle carrierConfig; @@ -820,6 +819,13 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa if (hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE)) { return true; } + + // Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS is available starting in O + if (VERSION.SDK_INT < VERSION_CODES.O) { + long timestampMillis = FilteredNumbersUtil.getLastEmergencyCallTimeMillis(context); + return isInEmergencyCallbackWindow(timestampMillis); + } + // We want to treat any incoming call that arrives a short time after an outgoing emergency call // as a potential emergency callback. if (getExtras() != null @@ -1270,39 +1276,28 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa didDismissVideoChargesAlertDialog = didDismiss; } - @Nullable - public Boolean isInGlobalSpamList() { - return isInGlobalSpamList; - } - - public void setIsInGlobalSpamList(boolean inSpamList) { - isInGlobalSpamList = inSpamList; - } - - @Nullable - public Boolean isInUserSpamList() { - return isInUserSpamList; + public void setSpamStatus(@Nullable SpamStatus spamStatus) { + this.spamStatus = spamStatus; } - public void setIsInUserSpamList(boolean inSpamList) { - isInUserSpamList = inSpamList; + public Optional<SpamStatus> getSpamStatus() { + return Optional.fromNullable(spamStatus); } - @Nullable - public Boolean isInUserWhiteList() { - return isInUserWhiteList; - } + public boolean isSpam() { + if (spamStatus == null || !spamStatus.isSpam()) { + return false; + } - public void setIsInUserWhiteList(boolean inWhiteList) { - isInUserWhiteList = inWhiteList; - } + if (!isIncoming()) { + return false; + } - public boolean isSpam() { - return isSpam; - } + if (isPotentialEmergencyCallback()) { + return false; + } - public void setSpam(boolean isSpam) { - this.isSpam = isSpam; + return true; } public boolean isBlocked() { diff --git a/java/com/android/incallui/speakeasy/SpeakEasyComponent.java b/java/com/android/incallui/speakeasy/SpeakEasyComponent.java index 320bc69ee..6dae44128 100644 --- a/java/com/android/incallui/speakeasy/SpeakEasyComponent.java +++ b/java/com/android/incallui/speakeasy/SpeakEasyComponent.java @@ -30,6 +30,8 @@ public abstract class SpeakEasyComponent { public abstract Optional<Fragment> speakEasySettingsFragment(); + public abstract Optional<Integer> speakEasyIcon(); + public static SpeakEasyComponent get(Context context) { return ((SpeakEasyComponent.HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) diff --git a/java/com/android/incallui/speakeasy/StubSpeakEasyModule.java b/java/com/android/incallui/speakeasy/StubSpeakEasyModule.java index d5f644372..67b564cb0 100644 --- a/java/com/android/incallui/speakeasy/StubSpeakEasyModule.java +++ b/java/com/android/incallui/speakeasy/StubSpeakEasyModule.java @@ -36,4 +36,9 @@ public abstract class StubSpeakEasyModule { static Optional<Fragment> provideSpeakEasySettingsFragment() { return Optional.absent(); } + + @Provides + static Optional<Integer> provideSpeakEasyIcon() { + return Optional.absent(); + } } |