Import translations. DO NOT MERGE am: 5fc22b92d2 -s ours am: 04d29c1e08 -s ours am: 0602dd0831 -s ours am: 2738f04ee3 -s ours
am: e66f6ecbd6 -s ours
Change-Id: Ia66dae309b17a0e73cec580a1d5555e5754a3115
diff --git a/Android.mk b/Android.mk
index efbdb09..13ca622 100644
--- a/Android.mk
+++ b/Android.mk
@@ -81,10 +81,12 @@
$(BASE_DIR)/dialer/calllogutils/res \
$(BASE_DIR)/dialer/common/res \
$(BASE_DIR)/dialer/contactactions/res \
+ $(BASE_DIR)/dialer/contactphoto/res \
$(BASE_DIR)/dialer/contactsfragment/res \
$(BASE_DIR)/dialer/dialpadview/res \
$(BASE_DIR)/dialer/enrichedcall/simulator/res \
$(BASE_DIR)/dialer/interactions/res \
+ $(BASE_DIR)/dialer/lettertile/res \
$(BASE_DIR)/dialer/main/impl/res \
$(BASE_DIR)/dialer/notification/res \
$(BASE_DIR)/dialer/oem/res \
@@ -118,9 +120,11 @@
$(BASE_DIR)/incallui/telecomeventui/res \
$(BASE_DIR)/incallui/video/impl/res \
$(BASE_DIR)/incallui/video/protocol/res \
+ $(BASE_DIR)/voicemail/impl/configui/res \
$(BASE_DIR)/voicemail/impl/res \
+
# Dialer manifest files to merge.
# find . -type f -name "AndroidManifest.xml" | uniq | sort
DIALER_MANIFEST_FILES += \
@@ -140,11 +144,13 @@
$(BASE_DIR)/dialer/calllogutils/AndroidManifest.xml \
$(BASE_DIR)/dialer/common/AndroidManifest.xml \
$(BASE_DIR)/dialer/contactactions/AndroidManifest.xml \
+ $(BASE_DIR)/dialer/contactphoto/AndroidManifest.xml \
$(BASE_DIR)/dialer/contactsfragment/AndroidManifest.xml \
$(BASE_DIR)/dialer/dialpadview/AndroidManifest.xml \
$(BASE_DIR)/dialer/enrichedcall/simulator/AndroidManifest.xml \
$(BASE_DIR)/dialer/interactions/AndroidManifest.xml \
$(BASE_DIR)/dialer/main/impl/AndroidManifest.xml \
+ $(BASE_DIR)/dialer/lettertile/AndroidManifest.xml \
$(BASE_DIR)/dialer/notification/AndroidManifest.xml \
$(BASE_DIR)/dialer/oem/AndroidManifest.xml \
$(BASE_DIR)/dialer/phonenumberutil/AndroidManifest.xml \
@@ -178,6 +184,7 @@
$(BASE_DIR)/incallui/video/impl/AndroidManifest.xml \
$(BASE_DIR)/incallui/video/protocol/AndroidManifest.xml \
$(BASE_DIR)/voicemail/AndroidManifest.xml \
+ $(BASE_DIR)/voicemail/impl/configui/AndroidManifest.xml \
$(BASE_DIR)/voicemail/impl/AndroidManifest.xml \
@@ -215,11 +222,13 @@
--extra-packages com.android.dialer.calllogutils \
--extra-packages com.android.dialer.common \
--extra-packages com.android.dialer.contactactions \
+ --extra-packages com.android.dialer.contactphoto \
--extra-packages com.android.dialer.contactsfragment \
--extra-packages com.android.dialer.dialpadview \
--extra-packages com.android.dialer.enrichedcall.simulator \
--extra-packages com.android.dialer.interactions \
--extra-packages com.android.dialer.main.impl \
+ --extra-packages com.android.dialer.lettertile \
--extra-packages com.android.dialer.notification \
--extra-packages com.android.dialer.oem \
--extra-packages com.android.dialer.phonenumberutil \
@@ -257,6 +266,7 @@
--extra-packages com.android.incallui.video.impl \
--extra-packages com.android.phone.common \
--extra-packages com.android.voicemail \
+ --extra-packages com.android.voicemail.impl.configui \
--extra-packages com.android.voicemail.impl \
--extra-packages com.android.voicemail.impl.fetch \
--extra-packages com.android.voicemail.impl.settings \
diff --git a/java/com/android/contacts/common/Bindings.java b/java/com/android/contacts/common/Bindings.java
deleted file mode 100644
index 29cf795..0000000
--- a/java/com/android/contacts/common/Bindings.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.common;
-
-import android.content.Context;
-import com.android.contacts.common.bindings.ContactsCommonBindings;
-import com.android.contacts.common.bindings.ContactsCommonBindingsFactory;
-import com.android.contacts.common.bindings.ContactsCommonBindingsStub;
-import java.util.Objects;
-
-/** Accessor for the contacts common bindings. */
-public class Bindings {
-
- private static ContactsCommonBindings instance;
-
- private Bindings() {}
-
- public static ContactsCommonBindings get(Context context) {
- Objects.requireNonNull(context);
- if (instance != null) {
- return instance;
- }
-
- Context application = context.getApplicationContext();
- if (application instanceof ContactsCommonBindingsFactory) {
- instance = ((ContactsCommonBindingsFactory) application).newContactsCommonBindings();
- }
-
- if (instance == null) {
- instance = new ContactsCommonBindingsStub();
- }
- return instance;
- }
-
- public static void setForTesting(ContactsCommonBindings testInstance) {
- instance = testInstance;
- }
-}
diff --git a/java/com/android/contacts/common/bindings/ContactsCommonBindings.java b/java/com/android/contacts/common/bindings/ContactsCommonBindings.java
deleted file mode 100644
index 44be53b..0000000
--- a/java/com/android/contacts/common/bindings/ContactsCommonBindings.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.contacts.common.bindings;
-
-import android.support.annotation.Nullable;
-
-/** Allows the container application to customize the contacts common library. */
-public interface ContactsCommonBindings {
-
- /** Builds a user agent string for the current application. */
- @Nullable
- String getUserAgent();
-}
diff --git a/java/com/android/contacts/common/bindings/ContactsCommonBindingsFactory.java b/java/com/android/contacts/common/bindings/ContactsCommonBindingsFactory.java
deleted file mode 100644
index 8958ad9..0000000
--- a/java/com/android/contacts/common/bindings/ContactsCommonBindingsFactory.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.contacts.common.bindings;
-
-/**
- * This interface should be implementated by the Application subclass. It allows the contacts common
- * module to get references to the ContactsCommonBindings.
- */
-public interface ContactsCommonBindingsFactory {
-
- ContactsCommonBindings newContactsCommonBindings();
-}
diff --git a/java/com/android/contacts/common/bindings/ContactsCommonBindingsStub.java b/java/com/android/contacts/common/bindings/ContactsCommonBindingsStub.java
deleted file mode 100644
index f2e21b1..0000000
--- a/java/com/android/contacts/common/bindings/ContactsCommonBindingsStub.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.contacts.common.bindings;
-
-import android.support.annotation.Nullable;
-
-/** Default implementation for contacts common bindings. */
-public class ContactsCommonBindingsStub implements ContactsCommonBindings {
-
- @Override
- @Nullable
- public String getUserAgent() {
- return null;
- }
-}
diff --git a/java/com/android/contacts/common/dialog/CallSubjectDialog.java b/java/com/android/contacts/common/dialog/CallSubjectDialog.java
index 88fac02..5c2ae2f 100644
--- a/java/com/android/contacts/common/dialog/CallSubjectDialog.java
+++ b/java/com/android/contacts/common/dialog/CallSubjectDialog.java
@@ -43,13 +43,13 @@
import android.widget.ListView;
import android.widget.QuickContactBadge;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.R;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.animation.AnimUtils;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.util.ViewUtil;
import java.nio.charset.Charset;
import java.util.ArrayList;
diff --git a/java/com/android/contacts/common/list/ContactEntryListAdapter.java b/java/com/android/contacts/common/list/ContactEntryListAdapter.java
index 7335297..117825d 100644
--- a/java/com/android/contacts/common/list/ContactEntryListAdapter.java
+++ b/java/com/android/contacts/common/list/ContactEntryListAdapter.java
@@ -32,8 +32,6 @@
import android.widget.QuickContactBadge;
import android.widget.SectionIndexer;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.DirectoryCompat;
@@ -41,6 +39,8 @@
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.configprovider.ConfigProviderBindings;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
import com.android.dialer.logging.InteractionEvent;
import com.android.dialer.logging.Logger;
import java.util.HashSet;
diff --git a/java/com/android/contacts/common/list/ContactEntryListFragment.java b/java/com/android/contacts/common/list/ContactEntryListFragment.java
index 04658be..94551a8 100644
--- a/java/com/android/contacts/common/list/ContactEntryListFragment.java
+++ b/java/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -43,10 +43,10 @@
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import com.android.common.widget.CompositeCursorAdapter.Partition;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.util.ContactListViewUtils;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.performancereport.PerformanceReport;
import java.lang.ref.WeakReference;
import java.util.Locale;
diff --git a/java/com/android/contacts/common/list/ContactListAdapter.java b/java/com/android/contacts/common/list/ContactListAdapter.java
index 6cd3118..721609d 100644
--- a/java/com/android/contacts/common/list/ContactListAdapter.java
+++ b/java/com/android/contacts/common/list/ContactListAdapter.java
@@ -23,9 +23,9 @@
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.SearchSnippets;
import android.view.ViewGroup;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.R;
import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
/**
* A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type. Also
diff --git a/java/com/android/contacts/common/list/ContactTileView.java b/java/com/android/contacts/common/list/ContactTileView.java
index 15582d6..4635641 100644
--- a/java/com/android/contacts/common/list/ContactTileView.java
+++ b/java/com/android/contacts/common/list/ContactTileView.java
@@ -23,13 +23,13 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.MoreContactUtils;
import com.android.contacts.common.R;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallSpecificAppData;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
/** A ContactTile displays a contact's picture and name */
public abstract class ContactTileView extends FrameLayout {
diff --git a/java/com/android/contacts/common/list/PhoneNumberListAdapter.java b/java/com/android/contacts/common/list/PhoneNumberListAdapter.java
index d1118c3..b742798 100644
--- a/java/com/android/contacts/common/list/PhoneNumberListAdapter.java
+++ b/java/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -30,23 +30,23 @@
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.CallableCompat;
import com.android.contacts.common.compat.DirectoryCompat;
import com.android.contacts.common.compat.PhoneCompat;
import com.android.contacts.common.extensions.PhoneDirectoryExtenderAccessor;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.contacts.common.list.ContactListItemView.CallToAction;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.util.Constants;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.CompatUtils;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
import com.android.dialer.dialercontact.DialerContact;
import com.android.dialer.enrichedcall.EnrichedCallCapabilities;
import com.android.dialer.enrichedcall.EnrichedCallComponent;
import com.android.dialer.enrichedcall.EnrichedCallManager;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.lightbringer.LightbringerComponent;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.util.CallUtil;
@@ -404,7 +404,7 @@
if (action == ContactListItemView.NONE) {
EnrichedCallManager manager = EnrichedCallComponent.get(mContext).getEnrichedCallManager();
EnrichedCallCapabilities capabilities = manager.getCapabilities(number);
- if (capabilities != null && capabilities.supportsCallComposer()) {
+ if (capabilities != null && capabilities.isCallComposerCapable()) {
action = ContactListItemView.CALL_AND_SHARE;
} else if (capabilities == null
&& getQueryString() != null
diff --git a/java/com/android/contacts/common/list/PhoneNumberPickerFragment.java b/java/com/android/contacts/common/list/PhoneNumberPickerFragment.java
index 558f3b2..2ab1217 100644
--- a/java/com/android/contacts/common/list/PhoneNumberPickerFragment.java
+++ b/java/com/android/contacts/common/list/PhoneNumberPickerFragment.java
@@ -353,7 +353,7 @@
if (view.getCallToAction() != ContactListItemView.NONE
|| view.getPhoneNumber() == null
|| manager.getCapabilities(view.getPhoneNumber()) == null
- || !manager.getCapabilities(view.getPhoneNumber()).supportsCallComposer()) {
+ || !manager.getCapabilities(view.getPhoneNumber()).isCallComposerCapable()) {
continue;
}
view.setCallToAction(ContactListItemView.CALL_AND_SHARE, listener, view.getPosition());
diff --git a/java/com/android/contacts/common/model/ContactLoader.java b/java/com/android/contacts/common/model/ContactLoader.java
index 7ef3b73..7ad1f71 100644
--- a/java/com/android/contacts/common/model/ContactLoader.java
+++ b/java/com/android/contacts/common/model/ContactLoader.java
@@ -44,10 +44,10 @@
import com.android.contacts.common.model.dataitem.PhotoDataItem;
import com.android.contacts.common.util.Constants;
import com.android.contacts.common.util.ContactLoaderUtils;
-import com.android.contacts.common.util.UriUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.util.PermissionsUtil;
+import com.android.dialer.util.UriUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
diff --git a/java/com/android/contacts/common/res/values/colors.xml b/java/com/android/contacts/common/res/values/colors.xml
index 20b28c9..ca87341 100644
--- a/java/com/android/contacts/common/res/values/colors.xml
+++ b/java/com/android/contacts/common/res/values/colors.xml
@@ -20,8 +20,6 @@
<color name="focus_color">#44ff0000</color>
- <color name="spam_contact_background">#A52714</color>
-
<!-- Color of ripples used for views with dark backgrounds -->
<color name="dialer_ripple_material_dark">#a0ffffff</color>
@@ -59,25 +57,6 @@
<color name="textColorIconOverlay">#fff</color>
<color name="textColorIconOverlayShadow">#000</color>
-
-
- <array name="letter_tile_colors">
- <item>#DB4437</item>
- <item>#E91E63</item>
- <item>#9C27B0</item>
- <item>#673AB7</item>
- <item>#3F51B5</item>
- <item>#4285F4</item>
- <item>#039BE5</item>
- <item>#0097A7</item>
- <item>#009688</item>
- <item>#0F9D58</item>
- <item>#689F38</item>
- <item>#EF6C00</item>
- <item>#FF5722</item>
- <item>#757575</item>
- </array>
-
<!-- Darker versions of letter_tile_colors, two shades darker. These colors are used
for settings secondary activity colors. -->
<array name="letter_tile_colors_dark">
@@ -104,11 +83,6 @@
this is Blue Grey 700 -->
<color name="quickcontact_default_photo_tint_color_dark">#455A64</color>
-
- <color name="letter_tile_default_color">#cccccc</color>
-
- <color name="letter_tile_font_color">#ffffff</color>
-
<color name="contactscommon_actionbar_background_color">@color/dialer_theme_color</color>
<!-- Color for icons in the actionbar -->
<color name="actionbar_icon_color">#ffffff</color>
diff --git a/java/com/android/contacts/common/res/values/dimens.xml b/java/com/android/contacts/common/res/values/dimens.xml
index 26f095f..74e1547 100644
--- a/java/com/android/contacts/common/res/values/dimens.xml
+++ b/java/com/android/contacts/common/res/values/dimens.xml
@@ -83,12 +83,6 @@
<dimen name="contact_phone_list_empty_description_size">20sp</dimen>
<dimen name="contact_phone_list_empty_description_padding">10dip</dimen>
- <!-- Dimensions for contact letter tiles -->
- <dimen name="tile_letter_font_size">40dp</dimen>
- <dimen name="tile_letter_font_size_small">20dp</dimen>
- <dimen name="tile_divider_width">1dp</dimen>
- <item name="letter_to_tile_ratio" type="dimen">67%</item>
-
<!-- Height of the floating action button -->
<dimen name="floating_action_button_height">56dp</dimen>
<!-- Width of the floating action button -->
diff --git a/java/com/android/contacts/common/res/values/strings.xml b/java/com/android/contacts/common/res/values/strings.xml
index 85866f7..f83f16b 100644
--- a/java/com/android/contacts/common/res/values/strings.xml
+++ b/java/com/android/contacts/common/res/values/strings.xml
@@ -182,13 +182,6 @@
<item quantity="other"><xliff:g id="count">%d</xliff:g> found</item>
</plurals>
- <!-- String describing the text for photo of a contact in a contacts list.
-
- Note: AccessibilityServices use this attribute to announce what the view represents.
- This is especially valuable for views without textual representation like ImageView.
- -->
- <string name="description_quick_contact_for">Quick contact for <xliff:g id="name">%1$s</xliff:g></string>
-
<!-- Shown as the display name for a person when the name is missing or unknown. [CHAR LIMIT=18]-->
<string name="missing_name">(No name)</string>
diff --git a/java/com/android/dialer/app/calllog/CallLogActivity.java b/java/com/android/dialer/app/calllog/CallLogActivity.java
index 35e05bc..c9e655d 100644
--- a/java/com/android/dialer/app/calllog/CallLogActivity.java
+++ b/java/com/android/dialer/app/calllog/CallLogActivity.java
@@ -32,10 +32,8 @@
import com.android.contacts.common.list.ViewPagerTabs;
import com.android.dialer.app.DialtactsActivity;
import com.android.dialer.app.R;
-import com.android.dialer.app.calllog.ClearCallLogDialog.Listener;
import com.android.dialer.calldetails.CallDetailsActivity;
import com.android.dialer.database.CallLogQueryHandler;
-import com.android.dialer.enrichedcall.EnrichedCallComponent;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.ScreenEvent;
import com.android.dialer.logging.UiAction;
@@ -46,7 +44,7 @@
/** Activity for viewing call history. */
public class CallLogActivity extends TransactionSafeActivity
- implements ViewPager.OnPageChangeListener, Listener {
+ implements ViewPager.OnPageChangeListener {
private static final int TAB_INDEX_ALL = 0;
private static final int TAB_INDEX_MISSED = 1;
@@ -148,7 +146,7 @@
startActivity(intent);
return true;
} else if (item.getItemId() == R.id.delete_all) {
- ClearCallLogDialog.show(getFragmentManager(), this);
+ ClearCallLogDialog.show(getFragmentManager());
return true;
}
return super.onOptionsItemSelected(item);
@@ -184,15 +182,6 @@
}
@Override
- public void callHistoryDeleted() {
- if (EnrichedCallComponent.get(this).getEnrichedCallManager().hasStoredData()) {
- Snackbar.make(
- findViewById(R.id.calllog_frame), getString(R.string.multiple_ec_data_deleted), 5_000)
- .show();
- }
- }
-
- @Override
public void onBackPressed() {
PerformanceReport.recordClick(UiAction.Type.PRESS_ANDROID_BACK_BUTTON);
super.onBackPressed();
diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java
index 41c9d60..5fcf59b 100644
--- a/java/com/android/dialer/app/calllog/CallLogAdapter.java
+++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java
@@ -344,10 +344,30 @@
// If enriched call capabilities were unknown on the initial load,
// viewHolder.isCallComposerCapable may be unset. Check here if we have the capabilities
// as a last attempt at getting them before showing the expanded view to the user
- EnrichedCallCapabilities capabilities =
- getEnrichedCallManager().getCapabilities(viewHolder.number);
- viewHolder.isCallComposerCapable =
- capabilities != null && capabilities.supportsCallComposer();
+ EnrichedCallCapabilities capabilities = null;
+
+ if (viewHolder.number != null) {
+ capabilities = getEnrichedCallManager().getCapabilities(viewHolder.number);
+ }
+
+ if (capabilities == null) {
+ capabilities = EnrichedCallCapabilities.NO_CAPABILITIES;
+ }
+
+ viewHolder.isCallComposerCapable = capabilities.isCallComposerCapable();
+
+ if (capabilities.isTemporarilyUnavailable()) {
+ LogUtil.i(
+ "mExpandCollapseListener.onClick",
+ "%s is temporarily unavailable, requesting capabilities",
+ LogUtil.sanitizePhoneNumber(viewHolder.number));
+ // Refresh the capabilities when temporarily unavailable, see go/ec-temp-unavailable.
+ // Similarly to when we request capabilities the first time, the 'Share and call' button
+ // won't pop in with the new capabilities. Instead the row needs to be collapsed and
+ // expanded again.
+ getEnrichedCallManager().requestCapabilities(viewHolder.number);
+ }
+
generateAndMapNewCallDetailsEntriesHistoryResults(
viewHolder.number,
viewHolder.getDetailedPhoneDetails(),
@@ -368,20 +388,30 @@
}
expandViewHolderActions(viewHolder);
- if (viewHolder.videoCallButtonView != null
- && viewHolder.videoCallButtonView.getVisibility() == View.VISIBLE
- && LightbringerComponent.get(mActivity).getLightbringer().getPackageName() != null
- && LightbringerComponent.get(mActivity)
- .getLightbringer()
- .getPackageName()
- .equals(
- ((IntentProvider) viewHolder.videoCallButtonView.getTag())
- .getIntent(mActivity)
- .getPackage())) {
+ if (isLightbringerCallButtonVisible(viewHolder.videoCallButtonView)) {
CallIntentBuilder.increaseLightbringerCallButtonAppearInExpandedCallLogItemCount();
}
}
}
+
+ private boolean isLightbringerCallButtonVisible(View videoCallButtonView) {
+ if (videoCallButtonView == null) {
+ return false;
+ }
+ if (videoCallButtonView.getVisibility() != View.VISIBLE) {
+ return false;
+ }
+ IntentProvider intentProvider = (IntentProvider) videoCallButtonView.getTag();
+ if (intentProvider == null) {
+ return false;
+ }
+ String packageName =
+ LightbringerComponent.get(mActivity).getLightbringer().getPackageName();
+ if (packageName == null) {
+ return false;
+ }
+ return packageName.equals(intentProvider.getIntent(mActivity).getPackage());
+ }
};
private void checkMarkCallLogEntry(CallLogListItemViewHolder viewHolder) {
@@ -869,7 +899,7 @@
getEnrichedCallManager().requestCapabilities(number);
return false;
}
- return capabilities.supportsCallComposer();
+ return capabilities.isCallComposerCapable();
}
@NonNull
diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
index 6b97bd6..23a00d7 100644
--- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
+++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java
@@ -50,12 +50,8 @@
import android.widget.TextView;
import android.widget.Toast;
import com.android.contacts.common.ClipboardUtils;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.dialog.CallSubjectDialog;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
-import com.android.contacts.common.lettertiles.LetterTileDrawable.ContactType;
-import com.android.contacts.common.util.UriUtils;
import com.android.dialer.app.DialtactsActivity;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.CallLogAdapter.OnActionModeStateChangedListener;
@@ -73,8 +69,11 @@
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.configprovider.ConfigProviderBindings;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.dialercontact.DialerContact;
import com.android.dialer.dialercontact.SimDetails;
+import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.lettertile.LetterTileDrawable.ContactType;
import com.android.dialer.lightbringer.Lightbringer;
import com.android.dialer.lightbringer.LightbringerComponent;
import com.android.dialer.logging.ContactSource;
@@ -91,6 +90,7 @@
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.CallUtil;
import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.UriUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -164,7 +164,7 @@
* The callable phone number for the current call log entry. Cached here as the call back intent
* is set only when the actions ViewStub is inflated.
*/
- public String number;
+ @Nullable public String number;
/** The post-dial numbers that are dialed following the phone number. */
public String postDialDigits;
/** The formatted phone number to display. */
@@ -933,7 +933,9 @@
contact.setNameOrNumber((String) nameOrNumber);
}
contact.setContactType(getContactType());
- contact.setNumber(number);
+ if (number != null) {
+ contact.setNumber(number);
+ }
/* second line of contact view. */
if (!TextUtils.isEmpty(info.name)) {
contact.setDisplayNumber(displayNumber);
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsService.java b/java/com/android/dialer/app/calllog/CallLogNotificationsService.java
index be1ebfb..84aedf8 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsService.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsService.java
@@ -24,7 +24,11 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.support.annotation.WorkerThread;
+import com.android.dialer.common.Assert;
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.telecom.TelecomUtil;
import com.android.dialer.util.PermissionsUtil;
@@ -108,6 +112,15 @@
context.startService(serviceIntent);
}
+ public static void cancelAllMissedCalls(Context context) {
+ LogUtil.enterBlock("CallLogNotificationsService.cancelAllMissedCalls");
+ DialerExecutorComponent.get(context)
+ .dialerExecutorFactory()
+ .createNonUiTaskBuilder(new CancelAllMissedCallsWorker())
+ .build()
+ .executeSerial(context);
+ }
+
public static PendingIntent createMarkAllNewVoicemailsAsOldIntent(@NonNull Context context) {
Intent intent = new Intent(context, CallLogNotificationsService.class);
intent.setAction(CallLogNotificationsService.ACTION_MARK_ALL_NEW_VOICEMAILS_AS_OLD);
@@ -122,13 +135,6 @@
return PendingIntent.getService(context, 0, intent, 0);
}
- public static void cancelAllMissedCalls(@NonNull Context context) {
- LogUtil.enterBlock("CallLogNotificationsService.cancelAllMissedCalls");
- Intent serviceIntent = new Intent(context, CallLogNotificationsService.class);
- serviceIntent.setAction(ACTION_CANCEL_ALL_MISSED_CALLS);
- context.startService(serviceIntent);
- }
-
public static PendingIntent createCancelAllMissedCallsPendingIntent(@NonNull Context context) {
Intent intent = new Intent(context, CallLogNotificationsService.class);
intent.setAction(ACTION_CANCEL_ALL_MISSED_CALLS);
@@ -174,9 +180,7 @@
MissedCallNotifier.getIstance(this).insertPostCallNotification(phoneNumber, note);
break;
case ACTION_CANCEL_ALL_MISSED_CALLS:
- CallLogNotificationsQueryHelper.markAllMissedCallsInCallLogAsRead(this);
- MissedCallNotifier.cancelAllMissedCallNotifications(this);
- TelecomUtil.cancelMissedCallsNotification(this);
+ cancelAllMissedCalls(this);
break;
case ACTION_CANCEL_SINGLE_MISSED_CALL:
Uri callUri = intent.getData();
@@ -196,4 +200,26 @@
break;
}
}
+
+ @WorkerThread
+ private static void cancelAllMissedCallsBackground(Context context) {
+ LogUtil.enterBlock("CallLogNotificationsService.cancelAllMissedCallsBackground");
+ Assert.isWorkerThread();
+ CallLogNotificationsQueryHelper.markAllMissedCallsInCallLogAsRead(context);
+ MissedCallNotifier.cancelAllMissedCallNotifications(context);
+ TelecomUtil.cancelMissedCallsNotification(context);
+ }
+
+ /** Worker that cancels all missed call notifications and updates call log entries. */
+ private static class CancelAllMissedCallsWorker implements Worker<Context, Void> {
+
+ @Nullable
+ @Override
+ public Void doInBackground(@Nullable Context context) throws Throwable {
+ if (context != null) {
+ cancelAllMissedCallsBackground(context);
+ }
+ return null;
+ }
+ }
}
diff --git a/java/com/android/dialer/app/calllog/ClearCallLogDialog.java b/java/com/android/dialer/app/calllog/ClearCallLogDialog.java
index 5c3d4d9..b16eb1b 100644
--- a/java/com/android/dialer/app/calllog/ClearCallLogDialog.java
+++ b/java/com/android/dialer/app/calllog/ClearCallLogDialog.java
@@ -22,76 +22,63 @@
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.app.ProgressDialog;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.CallLog.Calls;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
import com.android.dialer.app.R;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.concurrent.DialerExecutor;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.enrichedcall.EnrichedCallComponent;
import com.android.dialer.phonenumbercache.CachedNumberLookupService;
import com.android.dialer.phonenumbercache.PhoneNumberCache;
/** Dialog that clears the call log after confirming with the user */
public class ClearCallLogDialog extends DialogFragment {
- private Listener listener;
+ private DialerExecutor<Void> clearCallLogTask;
+ private ProgressDialog progressDialog;
/** Preferred way to show this dialog */
- public static void show(FragmentManager fragmentManager, @NonNull Listener listener) {
+ public static void show(FragmentManager fragmentManager) {
ClearCallLogDialog dialog = new ClearCallLogDialog();
- dialog.listener = Assert.isNotNull(listener);
dialog.show(fragmentManager, "deleteCallLog");
}
@Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ clearCallLogTask =
+ DialerExecutorComponent.get(getContext())
+ .dialerExecutorFactory()
+ .createUiTaskBuilder(
+ getFragmentManager(),
+ "clearCallLogTask",
+ new ClearCallLogWorker(getActivity().getApplicationContext()))
+ .onSuccess(this::onSuccess)
+ .build();
+ }
+
+ @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final ContentResolver resolver = getActivity().getContentResolver();
- final Context context = getActivity().getApplicationContext();
- final OnClickListener okListener =
- new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final ProgressDialog progressDialog =
- ProgressDialog.show(
- getActivity(), getString(R.string.clearCallLogProgress_title), "", true, false);
- progressDialog.setOwnerActivity(getActivity());
- CallLogNotificationsService.cancelAllMissedCalls(getContext());
- final AsyncTask<Void, Void, Void> task =
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- resolver.delete(Calls.CONTENT_URI, null, null);
- CachedNumberLookupService cachedNumberLookupService =
- PhoneNumberCache.get(context).getCachedNumberLookupService();
- if (cachedNumberLookupService != null) {
- cachedNumberLookupService.clearAllCacheEntries(context);
- }
- return null;
- }
+ OnClickListener okListener =
+ (dialog, which) -> {
+ progressDialog =
+ ProgressDialog.show(
+ getActivity(), getString(R.string.clearCallLogProgress_title), "", true, false);
+ progressDialog.setOwnerActivity(getActivity());
+ CallLogNotificationsService.cancelAllMissedCalls(getContext());
- @Override
- protected void onPostExecute(Void result) {
- final Activity activity = progressDialog.getOwnerActivity();
+ // TODO: Once we have the API, we should configure this ProgressDialog
+ // to only show up after a certain time (e.g. 150ms)
+ progressDialog.show();
- if (activity == null || activity.isDestroyed() || activity.isFinishing()) {
- return;
- }
-
- listener.callHistoryDeleted();
- if (progressDialog != null && progressDialog.isShowing()) {
- progressDialog.dismiss();
- }
- }
- };
- // TODO: Once we have the API, we should configure this ProgressDialog
- // to only show up after a certain time (e.g. 150ms)
- progressDialog.show();
- task.execute();
- }
+ clearCallLogTask.executeSerial(null);
};
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.clearCallLogConfirmation_title)
@@ -103,7 +90,48 @@
.create();
}
- interface Listener {
- void callHistoryDeleted();
+ private static class ClearCallLogWorker implements Worker<Void, Void> {
+ private final Context appContext;
+
+ private ClearCallLogWorker(Context appContext) {
+ this.appContext = appContext;
+ }
+
+ @Nullable
+ @Override
+ public Void doInBackground(@Nullable Void unused) throws Throwable {
+ appContext.getContentResolver().delete(Calls.CONTENT_URI, null, null);
+ CachedNumberLookupService cachedNumberLookupService =
+ PhoneNumberCache.get(appContext).getCachedNumberLookupService();
+ if (cachedNumberLookupService != null) {
+ cachedNumberLookupService.clearAllCacheEntries(appContext);
+ }
+ return null;
+ }
+ }
+
+ private void onSuccess(Void unused) {
+ Assert.isNotNull(progressDialog);
+ Activity activity = progressDialog.getOwnerActivity();
+
+ if (activity == null || activity.isDestroyed() || activity.isFinishing()) {
+ return;
+ }
+
+ maybeShowEnrichedCallSnackbar(activity);
+
+ if (progressDialog != null && progressDialog.isShowing()) {
+ progressDialog.dismiss();
+ }
+ }
+
+ private void maybeShowEnrichedCallSnackbar(Activity activity) {
+ if (EnrichedCallComponent.get(activity).getEnrichedCallManager().hasStoredData()) {
+ Snackbar.make(
+ activity.findViewById(R.id.calllog_frame),
+ getString(R.string.multiple_ec_data_deleted),
+ 5_000)
+ .show();
+ }
}
}
diff --git a/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java b/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java
index 4c8e32a..537acd0 100644
--- a/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java
+++ b/java/com/android/dialer/app/contactinfo/ContactPhotoLoader.java
@@ -25,10 +25,10 @@
import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.app.R;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.phonenumbercache.ContactInfoHelper;
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
index dbd4e86..ca12e43 100644
--- a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
@@ -20,9 +20,9 @@
import android.database.Cursor;
import android.telephony.PhoneNumberUtils;
import android.view.View;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.dialer.app.R;
import com.android.dialer.blocking.BlockNumberDialogFragment;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.logging.InteractionEvent;
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
index f53a458..db119ab 100644
--- a/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
@@ -31,7 +31,6 @@
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.app.R;
import com.android.dialer.blocking.BlockedNumbersMigrator;
import com.android.dialer.blocking.BlockedNumbersMigrator.Listener;
@@ -40,6 +39,7 @@
import com.android.dialer.blocking.FilteredNumbersUtil.CheckForSendToVoicemailContactListener;
import com.android.dialer.blocking.FilteredNumbersUtil.ImportSendToVoicemailContactsListener;
import com.android.dialer.database.FilteredNumberContract;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.voicemailstatus.VisualVoicemailEnabledChecker;
public class BlockedNumbersFragment extends ListFragment
diff --git a/java/com/android/dialer/app/filterednumber/NumbersAdapter.java b/java/com/android/dialer/app/filterednumber/NumbersAdapter.java
index d98395e..6e1d1a5 100644
--- a/java/com/android/dialer/app/filterednumber/NumbersAdapter.java
+++ b/java/com/android/dialer/app/filterednumber/NumbersAdapter.java
@@ -26,15 +26,15 @@
import android.widget.QuickContactBadge;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
-import com.android.contacts.common.util.UriUtils;
import com.android.dialer.app.R;
import com.android.dialer.compat.CompatUtils;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.phonenumbercache.ContactInfoHelper;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
+import com.android.dialer.util.UriUtils;
public class NumbersAdapter extends SimpleCursorAdapter {
diff --git a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java
index 313efb4..1e90eec 100644
--- a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java
+++ b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java
@@ -19,9 +19,9 @@
import android.content.Context;
import android.database.Cursor;
import android.view.View;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.dialer.app.R;
import com.android.dialer.blocking.FilteredNumbersUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.phonenumbercache.ContactInfoHelper;
diff --git a/java/com/android/dialer/app/list/OldSpeedDialFragment.java b/java/com/android/dialer/app/list/OldSpeedDialFragment.java
index 05d017b..afc7c13 100644
--- a/java/com/android/dialer/app/list/OldSpeedDialFragment.java
+++ b/java/com/android/dialer/app/list/OldSpeedDialFragment.java
@@ -45,13 +45,13 @@
import android.widget.FrameLayout.LayoutParams;
import android.widget.ImageView;
import android.widget.ListView;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactTileLoaderFactory;
import com.android.contacts.common.list.ContactTileView;
import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
import com.android.dialer.app.R;
import com.android.dialer.callintent.CallSpecificAppData;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.util.PermissionsUtil;
import com.android.dialer.util.ViewUtil;
import com.android.dialer.widget.EmptyContentView;
diff --git a/java/com/android/dialer/app/list/PhoneFavoriteTileView.java b/java/com/android/dialer/app/list/PhoneFavoriteTileView.java
index 30870eb..455085d 100644
--- a/java/com/android/dialer/app/list/PhoneFavoriteTileView.java
+++ b/java/com/android/dialer/app/list/PhoneFavoriteTileView.java
@@ -23,15 +23,15 @@
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.MoreContactUtils;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.contacts.common.list.ContactEntry;
import com.android.contacts.common.list.ContactTileView;
import com.android.dialer.app.R;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallSpecificAppData;
import com.android.dialer.callintent.SpeedDialContactType;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.logging.InteractionEvent;
import com.android.dialer.logging.Logger;
diff --git a/java/com/android/dialer/app/list/PhoneFavoritesTileAdapter.java b/java/com/android/dialer/app/list/PhoneFavoritesTileAdapter.java
index dbd601a..cd5712e 100644
--- a/java/com/android/dialer/app/list/PhoneFavoritesTileAdapter.java
+++ b/java/com/android/dialer/app/list/PhoneFavoritesTileAdapter.java
@@ -34,13 +34,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactTileLoaderFactory;
import com.android.contacts.common.list.ContactEntry;
import com.android.contacts.common.list.ContactTileView;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.dialer.app.R;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.lightbringer.Lightbringer;
import com.android.dialer.lightbringer.LightbringerComponent;
import com.android.dialer.logging.InteractionEvent;
diff --git a/java/com/android/dialer/app/res/layout/call_log_activity.xml b/java/com/android/dialer/app/res/layout/call_log_activity.xml
index 4e2b188..a5e5326 100644
--- a/java/com/android/dialer/app/res/layout/call_log_activity.xml
+++ b/java/com/android/dialer/app/res/layout/call_log_activity.xml
@@ -15,26 +15,27 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/calllog_frame"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:id="@+id/calllog_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_dialer_light"
+ android:orientation="vertical">
<com.android.contacts.common.list.ViewPagerTabs
- android:id="@+id/viewpager_header"
- style="@style/DialtactsActionBarTabTextStyle"
- android:layout_width="match_parent"
- android:layout_height="@dimen/tab_height"
- android:layout_gravity="top"
- android:elevation="@dimen/tab_elevation"
- android:orientation="horizontal"
- android:textAllCaps="true"/>
+ android:id="@+id/viewpager_header"
+ style="@style/DialtactsActionBarTabTextStyle"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/tab_height"
+ android:layout_gravity="top"
+ android:elevation="@dimen/tab_elevation"
+ android:orientation="horizontal"
+ android:textAllCaps="true"/>
<android.support.v4.view.ViewPager
- android:id="@+id/call_log_pager"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"/>
+ android:id="@+id/call_log_pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
<RelativeLayout
- android:id="@+id/floating_action_button_container"
- android:layout_width="0dp"
- android:layout_height="0dp"/>
+ android:id="@+id/floating_action_button_container"
+ android:layout_width="0dp"
+ android:layout_height="0dp"/>
</LinearLayout>
diff --git a/java/com/android/dialer/app/res/layout/call_log_fragment.xml b/java/com/android/dialer/app/res/layout/call_log_fragment.xml
index bbfe4e3..8bbec95 100644
--- a/java/com/android/dialer/app/res/layout/call_log_fragment.xml
+++ b/java/com/android/dialer/app/res/layout/call_log_fragment.xml
@@ -18,7 +18,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/background_dialer_call_log"
android:orientation="vertical">
<LinearLayout
@@ -64,7 +63,6 @@
android:paddingBottom="@dimen/floating_action_button_list_bottom_padding"
android:paddingStart="@dimen/call_log_horizontal_margin"
android:paddingEnd="@dimen/call_log_horizontal_margin"
- android:background="@color/background_dialer_call_log"
android:clipToPadding="false"/>
<com.android.dialer.widget.EmptyContentView
diff --git a/java/com/android/dialer/app/res/values/colors.xml b/java/com/android/dialer/app/res/values/colors.xml
index 2f6d87b..7a08dca 100644
--- a/java/com/android/dialer/app/res/values/colors.xml
+++ b/java/com/android/dialer/app/res/values/colors.xml
@@ -54,7 +54,6 @@
<!-- Background color for search results and call details -->
<color name="background_dialer_results">#f9f9f9</color>
- <color name="background_dialer_call_log">@color/background_dialer_light</color>
<!-- Color of the 1dp divider that separates favorites -->
<color name="favorite_contacts_separator_color">#d0d0d0</color>
diff --git a/java/com/android/dialer/app/voicemail/VoicemailAudioManager.java b/java/com/android/dialer/app/voicemail/VoicemailAudioManager.java
index 8d70cdb..d3c3820 100644
--- a/java/com/android/dialer/app/voicemail/VoicemailAudioManager.java
+++ b/java/com/android/dialer/app/voicemail/VoicemailAudioManager.java
@@ -86,6 +86,7 @@
if (newIsPluggedIn) {
newRoute = CallAudioState.ROUTE_WIRED_HEADSET;
} else {
+ mVoicemailPlaybackPresenter.pausePlayback();
if (mWasSpeakerOn) {
newRoute = CallAudioState.ROUTE_SPEAKER;
} else {
diff --git a/java/com/android/dialer/callcomposer/CallComposerActivity.java b/java/com/android/dialer/callcomposer/CallComposerActivity.java
index 0b4c20a..ddc1e87 100644
--- a/java/com/android/dialer/callcomposer/CallComposerActivity.java
+++ b/java/com/android/dialer/callcomposer/CallComposerActivity.java
@@ -32,6 +32,7 @@
import android.support.annotation.VisibleForTesting;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
+import android.support.v4.util.Pair;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v7.app.AppCompatActivity;
@@ -50,17 +51,18 @@
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.dialer.callcomposer.CallComposerFragment.CallComposerListener;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.UiUtil;
+import com.android.dialer.common.concurrent.DialerExecutor;
import com.android.dialer.common.concurrent.DialerExecutors;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.configprovider.ConfigProviderBindings;
import com.android.dialer.constants.Constants;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.dialercontact.DialerContact;
import com.android.dialer.enrichedcall.EnrichedCallComponent;
import com.android.dialer.enrichedcall.EnrichedCallManager;
@@ -139,6 +141,7 @@
private FrameLayout background;
private LinearLayout windowContainer;
+ private DialerExecutor<Uri> copyAndResizeExecutor;
private FastOutSlowInInterpolator interpolator;
private boolean shouldAnimateEntrance = true;
private boolean inFullscreenMode;
@@ -207,6 +210,29 @@
});
setMediaIconSelected(currentIndex);
+
+ copyAndResizeExecutor =
+ DialerExecutors.createUiTaskBuilder(
+ getFragmentManager(),
+ "copyAndResizeImageToSend",
+ new CopyAndResizeImageWorker(this.getApplicationContext()))
+ .onSuccess(this::onCopyAndResizeImageSuccess)
+ .onFailure(this::onCopyAndResizeImageFailure)
+ .build();
+ }
+
+ private void onCopyAndResizeImageSuccess(Pair<File, String> output) {
+ Uri shareableUri =
+ FileProvider.getUriForFile(
+ CallComposerActivity.this, Constants.get().getFileProviderAuthority(), output.first);
+
+ placeRCSCall(
+ MultimediaData.builder().setImage(grantUriPermission(shareableUri), output.second));
+ }
+
+ private void onCopyAndResizeImageFailure(Throwable throwable) {
+ // TODO(b/34279096) - gracefully handle message failure
+ LogUtil.e("CallComposerActivity.onCopyAndResizeImageFailure", "copy Failed", throwable);
}
@Override
@@ -332,28 +358,8 @@
GalleryComposerFragment galleryComposerFragment = (GalleryComposerFragment) fragment;
// If the current data is not a copy, make one.
if (!galleryComposerFragment.selectedDataIsCopy()) {
- DialerExecutors.createUiTaskBuilder(
- getFragmentManager(),
- "copyAndResizeImageToSend",
- new CopyAndResizeImageWorker(this.getApplicationContext()))
- .onSuccess(
- output -> {
- Uri shareableUri =
- FileProvider.getUriForFile(
- CallComposerActivity.this,
- Constants.get().getFileProviderAuthority(),
- output.first);
-
- builder.setImage(grantUriPermission(shareableUri), output.second);
- placeRCSCall(builder);
- })
- .onFailure(
- throwable -> {
- // TODO(b/34279096) - gracefully handle message failure
- LogUtil.e("CallComposerActivity.onCopyFailed", "copy Failed", throwable);
- })
- .build()
- .executeParallel(galleryComposerFragment.getGalleryData().getFileUri());
+ copyAndResizeExecutor.executeParallel(
+ galleryComposerFragment.getGalleryData().getFileUri());
} else {
Uri shareableUri =
FileProvider.getUriForFile(
diff --git a/java/com/android/dialer/callcomposer/CameraComposerFragment.java b/java/com/android/dialer/callcomposer/CameraComposerFragment.java
index d55f322..a5c65fd 100644
--- a/java/com/android/dialer/callcomposer/CameraComposerFragment.java
+++ b/java/com/android/dialer/callcomposer/CameraComposerFragment.java
@@ -18,13 +18,11 @@
import android.Manifest;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.drawable.Animatable;
import android.hardware.Camera.CameraInfo;
import android.net.Uri;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -57,7 +55,6 @@
public class CameraComposerFragment extends CallComposerFragment
implements CameraManagerListener, OnClickListener, CameraManager.MediaCallback {
- private static final String CAMERA_PRIVACY_PREF = "camera_privacy_permission";
private static final String CAMERA_DIRECTION_KEY = "camera_direction";
private static final String CAMERA_URI_KEY = "camera_key";
@@ -134,11 +131,8 @@
}
private void setupCamera() {
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
- if (!preferences.getBoolean(CAMERA_PRIVACY_PREF, false)) {
- Toast.makeText(getContext(), getString(R.string.camera_privacy_text), Toast.LENGTH_LONG)
- .show();
- preferences.edit().putBoolean(CAMERA_PRIVACY_PREF, true).apply();
+ if (!PermissionsUtil.hasCameraPrivacyToastShown(getContext())) {
+ PermissionsUtil.showCameraPermissionToast(getContext());
}
CameraManager.get().setListener(this);
preview.setShown();
@@ -403,6 +397,7 @@
Logger.get(getContext()).logImpression(DialerImpression.Type.CAMERA_PERMISSION_GRANTED);
LogUtil.i("CameraComposerFragment.onRequestPermissionsResult", "Permission granted.");
permissionView.setVisibility(View.GONE);
+ PermissionsUtil.setCameraPrivacyToastShown(getContext());
setupCamera();
} else if (requestCode == CAMERA_PERMISSION) {
Logger.get(getContext()).logImpression(DialerImpression.Type.CAMERA_PERMISSION_DENIED);
diff --git a/java/com/android/dialer/callcomposer/camera/CameraManager.java b/java/com/android/dialer/callcomposer/camera/CameraManager.java
index 783b57e..f79f654 100644
--- a/java/com/android/dialer/callcomposer/camera/CameraManager.java
+++ b/java/com/android/dialer/callcomposer/camera/CameraManager.java
@@ -35,6 +35,7 @@
import com.android.dialer.callcomposer.camera.camerafocus.RenderOverlay;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DialerExecutors;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -457,9 +458,9 @@
int height;
if (mRotation == 90 || mRotation == 270) {
// Is rotated, so swapping dimensions is desired
- //noinspection SuspiciousNameCombination
+ // noinspection SuspiciousNameCombination
width = size.height;
- //noinspection SuspiciousNameCombination
+ // noinspection SuspiciousNameCombination
height = size.width;
} else {
width = size.width;
@@ -467,9 +468,20 @@
}
LogUtil.i(
"CameraManager.onPictureTaken", "taken picture size: " + bytes.length + " bytes");
- new ImagePersistTask(
- width, height, heightPercent, bytes, mCameraPreview.getContext(), callback)
- .execute();
+ DialerExecutors.createNonUiTaskBuilder(
+ new ImagePersistWorker(
+ width, height, heightPercent, bytes, mCameraPreview.getContext()))
+ .onSuccess(
+ (result) -> {
+ callback.onMediaReady(
+ result.getUri(), "image/jpeg", result.getWidth(), result.getHeight());
+ })
+ .onFailure(
+ (throwable) -> {
+ callback.onMediaFailed(new Exception("Persisting image failed", throwable));
+ })
+ .build()
+ .executeSerial(null);
}
};
diff --git a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java b/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
similarity index 77%
rename from java/com/android/dialer/callcomposer/camera/ImagePersistTask.java
rename to java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
index 8620701..26b0bde 100644
--- a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java
+++ b/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
@@ -22,13 +22,16 @@
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
+import android.support.annotation.NonNull;
import android.support.v4.content.FileProvider;
+import com.android.dialer.callcomposer.camera.ImagePersistWorker.Result;
import com.android.dialer.callcomposer.camera.exif.ExifInterface;
import com.android.dialer.callcomposer.util.BitmapResizer;
import com.android.dialer.common.Assert;
-import com.android.dialer.common.concurrent.FallibleAsyncTask;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.constants.Constants;
import com.android.dialer.util.DialerUtils;
+import com.google.auto.value.AutoValue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -36,52 +39,70 @@
/** Persisting image routine. */
@TargetApi(VERSION_CODES.M)
-public class ImagePersistTask extends FallibleAsyncTask<Void, Void, Uri> {
+public class ImagePersistWorker implements Worker<Void, Result> {
private int mWidth;
private int mHeight;
private final float mHeightPercent;
private final byte[] mBytes;
private final Context mContext;
- private final CameraManager.MediaCallback mCallback;
- ImagePersistTask(
+ @AutoValue
+ abstract static class Result {
+
+ public static Builder builder() {
+ return new AutoValue_ImagePersistWorker_Result.Builder();
+ }
+
+ @NonNull
+ abstract Uri getUri();
+
+ abstract int getWidth();
+
+ abstract int getHeight();
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder setUri(@NonNull Uri uri);
+
+ abstract Builder setWidth(int width);
+
+ abstract Builder setHeight(int height);
+
+ abstract Result build();
+ }
+ }
+
+ ImagePersistWorker(
final int width,
final int height,
final float heightPercent,
final byte[] bytes,
- final Context context,
- final CameraManager.MediaCallback callback) {
+ final Context context) {
Assert.checkArgument(heightPercent >= 0 && heightPercent <= 1);
Assert.isNotNull(bytes);
Assert.isNotNull(context);
- Assert.isNotNull(callback);
mWidth = width;
mHeight = height;
mHeightPercent = heightPercent;
mBytes = bytes;
mContext = context;
- mCallback = callback;
}
@Override
- protected Uri doInBackgroundFallible(final Void... params) throws Exception {
+ public Result doInBackground(Void unused) throws Exception {
File outputFile = DialerUtils.createShareableFile(mContext);
try (OutputStream outputStream = new FileOutputStream(outputFile)) {
writeClippedBitmap(outputStream);
}
- return FileProvider.getUriForFile(
- mContext, Constants.get().getFileProviderAuthority(), outputFile);
- }
-
- @Override
- protected void onPostExecute(FallibleTaskResult<Uri> result) {
- if (result.isFailure()) {
- mCallback.onMediaFailed(new Exception("Persisting image failed", result.getThrowable()));
- } else {
- mCallback.onMediaReady(result.getResult(), "image/jpeg", mWidth, mHeight);
- }
+ return Result.builder()
+ .setUri(
+ FileProvider.getUriForFile(
+ mContext, Constants.get().getFileProviderAuthority(), outputFile))
+ .setWidth(mWidth)
+ .setHeight(mHeight)
+ .build();
}
private void writeClippedBitmap(OutputStream outputStream) throws IOException {
diff --git a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
index 3df3c3a..7d5757b 100644
--- a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
+++ b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
@@ -24,10 +24,10 @@
import android.view.View.OnClickListener;
import android.widget.QuickContactBadge;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.Assert;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.dialercontact.DialerContact;
import com.android.dialer.logging.DialerImpression;
import com.android.dialer.logging.InteractionEvent;
diff --git a/java/com/android/dialer/calldetails/res/layout/contact_container.xml b/java/com/android/dialer/calldetails/res/layout/contact_container.xml
index 0911291..b01a6cc 100644
--- a/java/com/android/dialer/calldetails/res/layout/contact_container.xml
+++ b/java/com/android/dialer/calldetails/res/layout/contact_container.xml
@@ -31,8 +31,7 @@
android:layout_height="@dimen/call_details_contact_photo_size"
android:layout_centerVertical="true"
android:padding="@dimen/call_details_contact_photo_padding"
- android:focusable="true"
- android:contentDescription="@string/description_quick_contact_for"/>
+ android:focusable="true"/>
<LinearLayout
android:orientation="vertical"
diff --git a/java/com/android/dialer/calllogutils/CallEntryFormatter.java b/java/com/android/dialer/calllogutils/CallEntryFormatter.java
index 6aa93af..c5ec157 100644
--- a/java/com/android/dialer/calllogutils/CallEntryFormatter.java
+++ b/java/com/android/dialer/calllogutils/CallEntryFormatter.java
@@ -95,9 +95,29 @@
// example output: "1s"
formatPattern =
context.getString(R.string.call_duration_short_format_pattern, "s", secondsString);
+
+ // Temporary work around for a broken Hebrew(iw) translation.
+ if (formatPattern.endsWith("\'\'")) {
+ formatPattern = formatPattern.substring(0, formatPattern.length() - 1);
+ }
}
- SimpleDateFormat format = new SimpleDateFormat(formatPattern);
- return format.format(new Date(TimeUnit.SECONDS.toMillis(elapsedSeconds)));
+
+ // If new translation issues arise, we should catch them here to prevent crashes.
+ try {
+ Date date = new Date(TimeUnit.SECONDS.toMillis(elapsedSeconds));
+ SimpleDateFormat format = new SimpleDateFormat(formatPattern);
+ String duration = format.format(date);
+
+ // SimpleDateFormat cannot display more than 59 minutes, instead it displays MINUTES % 60.
+ // Here we check for that value and replace it with the correct value.
+ if (elapsedSeconds >= TimeUnit.MINUTES.toSeconds(60)) {
+ int minutes = (int) (elapsedSeconds / 60);
+ duration = duration.replaceFirst(Integer.toString(minutes % 60), Integer.toString(minutes));
+ }
+ return duration;
+ } catch (Exception e) {
+ return "";
+ }
}
private static CharSequence formatDurationA11y(Context context, long elapsedSeconds) {
diff --git a/java/com/android/dialer/common/AndroidManifest.xml b/java/com/android/dialer/common/AndroidManifest.xml
index ae43d66..8892b58 100644
--- a/java/com/android/dialer/common/AndroidManifest.xml
+++ b/java/com/android/dialer/common/AndroidManifest.xml
@@ -1,3 +1,18 @@
+<!--
+ ~ 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
+ -->
<manifest
package="com.android.dialer.common">
</manifest>
diff --git a/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java b/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java
index 82e517d..a87bbce 100644
--- a/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java
+++ b/java/com/android/dialer/common/concurrent/DefaultDialerExecutorFactory.java
@@ -166,17 +166,7 @@
});
private static final Executor defaultParallelExecutor =
- Executors.newFixedThreadPool(
- 5,
- new ThreadFactory() {
- @Override
- public Thread newThread(Runnable runnable) {
- LogUtil.i("NonUiTaskBuilder.newThread", "creating parallel thread");
- Thread thread = new Thread(runnable, "NonUiTaskBuilder-Parallel");
- thread.setPriority(4); // Corresponds to Process.THREAD_PRIORITY_BACKGROUND
- return thread;
- }
- });
+ DialerExecutors.getLowPriorityThreadPool();
NonUiTaskBuilder(Worker<InputT, OutputT> worker) {
this(worker, defaultSerialExecutorService, defaultParallelExecutor);
diff --git a/java/com/android/dialer/common/concurrent/DialerExecutors.java b/java/com/android/dialer/common/concurrent/DialerExecutors.java
index 148d866..81b3c5c 100644
--- a/java/com/android/dialer/common/concurrent/DialerExecutors.java
+++ b/java/com/android/dialer/common/concurrent/DialerExecutors.java
@@ -19,7 +19,11 @@
import android.app.FragmentManager;
import android.support.annotation.NonNull;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
/**
* Factory methods for creating {@link DialerExecutor} objects for doing background work.
@@ -131,4 +135,27 @@
@NonNull Worker<InputT, OutputT> worker) {
return new DefaultDialerExecutorFactory().createNonUiTaskBuilder(Assert.isNotNull(worker));
}
+
+ private static final Executor lowPriorityThreadPool =
+ Executors.newFixedThreadPool(
+ 5,
+ new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable runnable) {
+ LogUtil.i("DialerExecutors.newThread", "creating low priority thread");
+ Thread thread = new Thread(runnable, "DialerExecutors-LowPriority");
+ thread.setPriority(4); // Corresponds to Process.THREAD_PRIORITY_BACKGROUND
+ return thread;
+ }
+ });
+
+ /**
+ * An application-wide thread pool used for low priority (non-UI) tasks.
+ *
+ * <p>This exists to prevent each individual dialer component from having to create its own
+ * threads/pools, which would result in the application having more threads than really necessary.
+ */
+ public static Executor getLowPriorityThreadPool() {
+ return lowPriorityThreadPool;
+ }
}
diff --git a/java/com/android/dialer/common/concurrent/FallibleAsyncTask.java b/java/com/android/dialer/common/concurrent/FallibleAsyncTask.java
index 6d02fe6..c7a7f36 100644
--- a/java/com/android/dialer/common/concurrent/FallibleAsyncTask.java
+++ b/java/com/android/dialer/common/concurrent/FallibleAsyncTask.java
@@ -30,7 +30,9 @@
* @param <ParamsT> the type of the parameters sent to the task upon execution
* @param <ProgressT> the type of the progress units published during the background computation
* @param <ResultT> the type of the result of the background computation
+ * @deprecated Please use {@link DialerExecutors}.
*/
+@Deprecated
public abstract class FallibleAsyncTask<ParamsT, ProgressT, ResultT>
extends AsyncTask<ParamsT, ProgressT, FallibleTaskResult<ResultT>> {
diff --git a/java/com/android/dialer/common/res/values/strings.xml b/java/com/android/dialer/common/res/values/strings.xml
index 8e96161..770f42f 100644
--- a/java/com/android/dialer/common/res/values/strings.xml
+++ b/java/com/android/dialer/common/res/values/strings.xml
@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
<resources>
<string name="network_name_wifi">Wifi</string>
<string name="network_name_mobile">Mobile</string>
diff --git a/java/com/android/dialer/constants/Constants.java b/java/com/android/dialer/constants/Constants.java
index 076393e..f9d07e3 100644
--- a/java/com/android/dialer/constants/Constants.java
+++ b/java/com/android/dialer/constants/Constants.java
@@ -16,6 +16,7 @@
package com.android.dialer.constants;
+import android.content.Context;
import android.support.annotation.NonNull;
import com.android.dialer.common.Assert;
import com.android.dialer.proguard.UsedByReflection;
@@ -56,5 +57,7 @@
@NonNull
public abstract String getAnnotatedCallLogProviderAuthority();
+ public abstract String getUserAgent(Context context);
+
protected Constants() {}
}
diff --git a/java/com/android/dialer/constants/TrafficStatsTags.java b/java/com/android/dialer/constants/TrafficStatsTags.java
index b473402..1eca784 100644
--- a/java/com/android/dialer/constants/TrafficStatsTags.java
+++ b/java/com/android/dialer/constants/TrafficStatsTags.java
@@ -18,17 +18,16 @@
/** Registry of tags for {@link android.net.TrafficStats#setThreadStatsTag(int)} */
public class TrafficStatsTags {
- public static final int CONTACT_PHOTO_DOWNLOAD_TAG = 0x0001;
- public static final int NEARBY_PLACES_TAG = 0xaaaa;
- public static final int REVERSE_LOOKUP_CONTACT_TAG = 0xbaaa;
- public static final int REVERSE_LOOKUP_IMAGE_TAG = 0xbaab;
- public static final int DOWNLOAD_LOCATION_MAP_TAG = 0xd000;
- public static final int REVERSE_GEOCODE_TAG = 0xd001;
- public static final int VISUAL_VOICEMAIL_TAG = 0xd002;
- public static final int DIALER_VOIP_TAG = 0xd003;
+ public static final int CONTACT_PHOTO_DOWNLOAD_TAG = 0x00000001;
+ public static final int NEARBY_PLACES_TAG = 0x00000002;
+ public static final int REVERSE_LOOKUP_CONTACT_TAG = 0x00000003;
+ public static final int REVERSE_LOOKUP_IMAGE_TAG = 0x00000004;
+ public static final int DOWNLOAD_LOCATION_MAP_TAG = 0x00000005;
+ public static final int REVERSE_GEOCODE_TAG = 0x00000006;
+ public static final int VISUAL_VOICEMAIL_TAG = 0x00000007;
- // 0xFFFFFE00 to 0xFFFFFF00 reserved for proprietary extensions to the dialer app.
+ // 0xfffffe00 to 0xffffff00 reserved for proprietary extensions to the dialer app.
- // 0xFFFFFF00 to 0xFFFFFFFF reserved by the system (see TrafficStats#getAndSetThreadStatsTag)
+ // 0xffffff00 to 0xffffffff reserved by the system (see TrafficStats#getAndSetThreadStatsTag)
}
diff --git a/java/com/android/dialer/constants/aospdialer/ConstantsImpl.java b/java/com/android/dialer/constants/aospdialer/ConstantsImpl.java
index 1111732..38fd24b 100644
--- a/java/com/android/dialer/constants/aospdialer/ConstantsImpl.java
+++ b/java/com/android/dialer/constants/aospdialer/ConstantsImpl.java
@@ -16,6 +16,7 @@
package com.android.dialer.constants;
+import android.content.Context;
import android.support.annotation.NonNull;
import com.android.dialer.proguard.UsedByReflection;
@@ -40,4 +41,9 @@
public String getAnnotatedCallLogProviderAuthority() {
return "com.android.dialer.annotatedcalllog";
}
+
+ @Override
+ public String getUserAgent(Context context) {
+ return null;
+ }
}
diff --git a/java/com/android/dialer/constants/googledialer/ConstantsImpl.java b/java/com/android/dialer/constants/googledialer/ConstantsImpl.java
index 28d8b25..e151344 100644
--- a/java/com/android/dialer/constants/googledialer/ConstantsImpl.java
+++ b/java/com/android/dialer/constants/googledialer/ConstantsImpl.java
@@ -16,6 +16,9 @@
package com.android.dialer.constants;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
import android.support.annotation.NonNull;
import com.android.dialer.proguard.UsedByReflection;
@@ -40,4 +43,19 @@
public String getAnnotatedCallLogProviderAuthority() {
return "com.google.android.dialer.annotatedcalllog";
}
+
+ @Override
+ public String getUserAgent(Context context) {
+ StringBuilder userAgent = new StringBuilder("GoogleDialer ");
+ try {
+ String versionName =
+ context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
+ userAgent.append(versionName).append(" ");
+ } catch (PackageManager.NameNotFoundException e) {
+ // ignore
+ }
+ userAgent.append(Build.FINGERPRINT);
+
+ return userAgent.toString();
+ }
}
diff --git a/java/com/android/dialer/contactactions/ContactActionBottomSheet.java b/java/com/android/dialer/contactactions/ContactActionBottomSheet.java
index 56c8a94..9bf7ca0 100644
--- a/java/com/android/dialer/contactactions/ContactActionBottomSheet.java
+++ b/java/com/android/dialer/contactactions/ContactActionBottomSheet.java
@@ -28,8 +28,8 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.dialer.common.Assert;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.dialercontact.DialerContact;
import java.util.List;
diff --git a/java/com/android/dialer/contactphoto/AndroidManifest.xml b/java/com/android/dialer/contactphoto/AndroidManifest.xml
new file mode 100644
index 0000000..d852d40
--- /dev/null
+++ b/java/com/android/dialer/contactphoto/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<!--
+ ~ 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
+ -->
+<manifest
+ package="com.android.dialer.contactphoto">
+</manifest>
\ No newline at end of file
diff --git a/java/com/android/contacts/common/util/BitmapUtil.java b/java/com/android/dialer/contactphoto/BitmapUtil.java
similarity index 98%
rename from java/com/android/contacts/common/util/BitmapUtil.java
rename to java/com/android/dialer/contactphoto/BitmapUtil.java
index 51f65f2..36055e2 100644
--- a/java/com/android/contacts/common/util/BitmapUtil.java
+++ b/java/com/android/dialer/contactphoto/BitmapUtil.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.common.util;
+package com.android.dialer.contactphoto;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
diff --git a/java/com/android/contacts/common/ContactPhotoManager.java b/java/com/android/dialer/contactphoto/ContactPhotoManager.java
similarity index 98%
rename from java/com/android/contacts/common/ContactPhotoManager.java
rename to java/com/android/dialer/contactphoto/ContactPhotoManager.java
index fbf51cc..4598379 100644
--- a/java/com/android/contacts/common/ContactPhotoManager.java
+++ b/java/com/android/dialer/contactphoto/ContactPhotoManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.common;
+package com.android.dialer.contactphoto;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -28,10 +28,10 @@
import android.view.View;
import android.widget.ImageView;
import android.widget.QuickContactBadge;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
-import com.android.contacts.common.util.UriUtils;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.util.PermissionsUtil;
+import com.android.dialer.util.UriUtils;
/** Asynchronously loads contact photos and maintains a cache of photos. */
public abstract class ContactPhotoManager implements ComponentCallbacks2 {
diff --git a/java/com/android/contacts/common/ContactPhotoManagerImpl.java b/java/com/android/dialer/contactphoto/ContactPhotoManagerImpl.java
similarity index 97%
rename from java/com/android/contacts/common/ContactPhotoManagerImpl.java
rename to java/com/android/dialer/contactphoto/ContactPhotoManagerImpl.java
index 28ecf34..4ad7ea4 100644
--- a/java/com/android/contacts/common/ContactPhotoManagerImpl.java
+++ b/java/com/android/dialer/contactphoto/ContactPhotoManagerImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.common;
+package com.android.dialer.contactphoto;
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
@@ -52,11 +52,11 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
-import com.android.contacts.common.util.BitmapUtil;
-import com.android.contacts.common.util.UriUtils;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.constants.Constants;
import com.android.dialer.constants.TrafficStatsTags;
import com.android.dialer.util.PermissionsUtil;
+import com.android.dialer.util.UriUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -197,7 +197,7 @@
context.getResources().getDimensionPixelSize(R.dimen.contact_browser_list_item_photo_size);
// Get a user agent string to use for URI photo requests.
- mUserAgent = Bindings.get(context).getUserAgent();
+ mUserAgent = Constants.get().getUserAgent(context);
if (mUserAgent == null) {
mUserAgent = "";
}
@@ -1220,20 +1220,23 @@
InputStream is = null;
if (scheme.equals("http") || scheme.equals("https")) {
TrafficStats.setThreadStatsTag(TrafficStatsTags.CONTACT_PHOTO_DOWNLOAD_TAG);
- final HttpURLConnection connection =
- (HttpURLConnection) new URL(uri.toString()).openConnection();
-
- // Include the user agent if it is specified.
- if (!TextUtils.isEmpty(mUserAgent)) {
- connection.setRequestProperty("User-Agent", mUserAgent);
- }
try {
- is = connection.getInputStream();
- } catch (IOException e) {
- connection.disconnect();
- is = null;
+ final HttpURLConnection connection =
+ (HttpURLConnection) new URL(uri.toString()).openConnection();
+
+ // Include the user agent if it is specified.
+ if (!TextUtils.isEmpty(mUserAgent)) {
+ connection.setRequestProperty("User-Agent", mUserAgent);
+ }
+ try {
+ is = connection.getInputStream();
+ } catch (IOException e) {
+ connection.disconnect();
+ is = null;
+ }
+ } finally {
+ TrafficStats.clearThreadStatsTag();
}
- TrafficStats.clearThreadStatsTag();
} else {
is = mResolver.openInputStream(uri);
}
diff --git a/java/com/android/dialer/contactphoto/res/values/dimens.xml b/java/com/android/dialer/contactphoto/res/values/dimens.xml
new file mode 100644
index 0000000..7c3361a
--- /dev/null
+++ b/java/com/android/dialer/contactphoto/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<resources>
+ <dimen name="contact_browser_list_item_photo_size">40dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/contactphoto/res/values/strings.xml b/java/com/android/dialer/contactphoto/res/values/strings.xml
new file mode 100644
index 0000000..5b050d8
--- /dev/null
+++ b/java/com/android/dialer/contactphoto/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2012 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
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- String describing the text for photo of a contact in a contacts list.
+
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ This is especially valuable for views without textual representation like ImageView.
+ -->
+ <string name="description_quick_contact_for">Quick contact for <xliff:g id="name">%1$s</xliff:g></string>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/contactsfragment/ContactsAdapter.java b/java/com/android/dialer/contactsfragment/ContactsAdapter.java
index d8ee3d1..1bd8e34 100644
--- a/java/com/android/dialer/contactsfragment/ContactsAdapter.java
+++ b/java/com/android/dialer/contactsfragment/ContactsAdapter.java
@@ -26,9 +26,9 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.common.Assert;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.lettertile.LetterTileDrawable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -137,7 +137,7 @@
@Override
public int getItemCount() {
- return (cursor == null ? 0 : cursor.getCount()) + 1; // add contact
+ return (cursor == null || cursor.isClosed() ? 0 : cursor.getCount()) + 1; // add contact
}
private static String getDisplayName(Cursor cursor) {
diff --git a/java/com/android/dialer/contactsfragment/ContactsFragment.java b/java/com/android/dialer/contactsfragment/ContactsFragment.java
index 41fa8f9..50c9fe8 100644
--- a/java/com/android/dialer/contactsfragment/ContactsFragment.java
+++ b/java/com/android/dialer/contactsfragment/ContactsFragment.java
@@ -122,8 +122,10 @@
emptyContentView.setDescription(R.string.all_contacts_empty);
emptyContentView.setActionLabel(R.string.all_contacts_empty_add_contact_action);
emptyContentView.setVisibility(View.VISIBLE);
+ recyclerView.setVisibility(View.GONE);
} else {
emptyContentView.setVisibility(View.GONE);
+ recyclerView.setVisibility(View.VISIBLE);
adapter = new ContactsAdapter(getContext(), cursor);
manager =
new LinearLayoutManager(getContext()) {
diff --git a/java/com/android/dialer/database/CallLogQueryHandler.java b/java/com/android/dialer/database/CallLogQueryHandler.java
index 35f7854..4ccf68e 100644
--- a/java/com/android/dialer/database/CallLogQueryHandler.java
+++ b/java/com/android/dialer/database/CallLogQueryHandler.java
@@ -190,6 +190,18 @@
.appendOmtpVoicemailSelectionClause(mContext, where, selectionArgs);
}
+ // Filter out all Duo entries other than video calls
+ where
+ .append(" AND (")
+ .append(Calls.PHONE_ACCOUNT_COMPONENT_NAME)
+ .append(" NOT LIKE 'com.google.android.apps.tachyon%' OR ")
+ .append(Calls.FEATURES)
+ .append(" & ")
+ .append(Calls.FEATURES_VIDEO)
+ .append(" == ")
+ .append(Calls.FEATURES_VIDEO)
+ .append(")");
+
final int limit = (mLogLimit == -1) ? NUM_LOGS_TO_DISPLAY : mLogLimit;
final String selection = where.length() > 0 ? where.toString() : null;
Uri uri =
diff --git a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_one.xml b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_one.xml
index 6f178f0..1356246 100644
--- a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_one.xml
+++ b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_one.xml
@@ -35,7 +35,7 @@
<ImageView
android:id="@+id/dialpad_key_voicemail"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/dialpad_voicemail_icon_size"
android:scaleType="fitCenter"
android:src="@drawable/quantum_ic_voicemail_white_24"
android:tint="@color/dialpad_voicemail_tint"/>
diff --git a/java/com/android/dialer/dialpadview/res/layout/dialpad_key_one.xml b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_one.xml
index 8859440..4401c5b 100644
--- a/java/com/android/dialer/dialpadview/res/layout/dialpad_key_one.xml
+++ b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_one.xml
@@ -18,7 +18,8 @@
android:id="@+id/one"
style="@style/DialpadKeyButtonStyle">
<LinearLayout
- style="@style/DialpadKeyInternalLayoutStyle">
+ android:layout_marginTop="1dp"
+ style="@style/DialpadKeyInternalLayoutStyle">
<com.android.dialer.dialpadview.DialpadTextView
android:id="@+id/dialpad_key_number"
style="@style/DialpadKeyNumberStyle"/>
@@ -28,9 +29,8 @@
<ImageView
android:id="@+id/dialpad_key_voicemail"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/dialpad_voicemail_icon_size"
android:layout_centerInParent="true"
- android:paddingTop="@dimen/dialpad_voicemail_icon_padding_top"
android:scaleType="fitCenter"
android:src="@drawable/quantum_ic_voicemail_white_24"
android:tint="?attr/dialpad_voicemail_tint"/>
diff --git a/java/com/android/dialer/dialpadview/res/values/dimens.xml b/java/com/android/dialer/dialpadview/res/values/dimens.xml
index 7277364..187ec9a 100644
--- a/java/com/android/dialer/dialpadview/res/values/dimens.xml
+++ b/java/com/android/dialer/dialpadview/res/values/dimens.xml
@@ -35,7 +35,7 @@
<dimen name="dialpad_digits_menu_right_padding">10dp</dimen>
<dimen name="dialpad_center_margin">3dp</dimen>
<dimen name="dialpad_button_margin">2dp</dimen>
- <dimen name="dialpad_voicemail_icon_padding_top">2dp</dimen>
+ <dimen name="dialpad_voicemail_icon_size">18dp</dimen>
<dimen name="dialpad_key_button_translate_y">100dp</dimen>
<dimen name="dialpad_overflow_margin">8dp</dimen>
<dimen name="dialpad_space_above_keys">14dp</dimen>
diff --git a/java/com/android/dialer/enrichedcall/EnrichedCallCapabilities.java b/java/com/android/dialer/enrichedcall/EnrichedCallCapabilities.java
index c3c78c9..32054e8 100644
--- a/java/com/android/dialer/enrichedcall/EnrichedCallCapabilities.java
+++ b/java/com/android/dialer/enrichedcall/EnrichedCallCapabilities.java
@@ -22,18 +22,53 @@
@AutoValue
public abstract class EnrichedCallCapabilities {
- public static final EnrichedCallCapabilities NO_CAPABILITIES =
- EnrichedCallCapabilities.create(false, false, false);
+ public static final EnrichedCallCapabilities NO_CAPABILITIES = builder().build();
- public static EnrichedCallCapabilities create(
- boolean supportsCallComposer, boolean supportsPostCall, boolean supportsVideoCall) {
- return new AutoValue_EnrichedCallCapabilities(
- supportsCallComposer, supportsPostCall, supportsVideoCall);
+ public static final EnrichedCallCapabilities ALL_CAPABILITIES =
+ builder()
+ .setCallComposerCapable(true)
+ .setPostCallCapable(true)
+ .setVideoShareCapable(true)
+ .build();
+
+ public abstract boolean isCallComposerCapable();
+
+ public abstract boolean isPostCallCapable();
+
+ public abstract boolean isVideoShareCapable();
+
+ public abstract Builder toBuilder();
+
+ /**
+ * Returns {@code true} if these capabilities represent those of a user that is temporarily
+ * unavailable. This is an indication that capabilities should be refreshed.
+ */
+ public abstract boolean isTemporarilyUnavailable();
+
+ /**
+ * Creates an instance of {@link Builder}.
+ *
+ * <p>Unless otherwise set, all fields will default to false.
+ */
+ public static Builder builder() {
+ return new AutoValue_EnrichedCallCapabilities.Builder()
+ .setCallComposerCapable(false)
+ .setPostCallCapable(false)
+ .setVideoShareCapable(false)
+ .setTemporarilyUnavailable(false);
}
- public abstract boolean supportsCallComposer();
+ /** Creates instances of {@link EnrichedCallCapabilities}. */
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract Builder setCallComposerCapable(boolean isCapable);
- public abstract boolean supportsPostCall();
+ public abstract Builder setPostCallCapable(boolean isCapable);
- public abstract boolean supportsVideoShare();
+ public abstract Builder setVideoShareCapable(boolean isCapable);
+
+ public abstract Builder setTemporarilyUnavailable(boolean temporarilyUnavailable);
+
+ public abstract EnrichedCallCapabilities build();
+ }
}
diff --git a/java/com/android/dialer/enrichedcall/FuzzyPhoneNumberMatcher.java b/java/com/android/dialer/enrichedcall/FuzzyPhoneNumberMatcher.java
index 27dc0e9..6f4d975 100644
--- a/java/com/android/dialer/enrichedcall/FuzzyPhoneNumberMatcher.java
+++ b/java/com/android/dialer/enrichedcall/FuzzyPhoneNumberMatcher.java
@@ -29,25 +29,34 @@
* too slow, so character by character matching is used instead.
*/
public static boolean matches(@NonNull String lhs, @NonNull String rhs) {
- int aIndex = lhs.length() - 1;
- int bIndex = rhs.length() - 1;
+ return lastSevenDigitsCharacterByCharacterMatches(lhs, rhs);
+ }
+
+ /**
+ * This strategy examines the numbers character by character starting from the end. If the last
+ * {@link #REQUIRED_MATCHED_DIGITS} match, it returns {@code true}.
+ */
+ private static boolean lastSevenDigitsCharacterByCharacterMatches(
+ @NonNull String lhs, @NonNull String rhs) {
+ int lhsIndex = lhs.length() - 1;
+ int rhsIndex = rhs.length() - 1;
int matchedDigits = 0;
- while (aIndex >= 0 && bIndex >= 0) {
- if (!Character.isDigit(lhs.charAt(aIndex))) {
- --aIndex;
+ while (lhsIndex >= 0 && rhsIndex >= 0) {
+ if (!Character.isDigit(lhs.charAt(lhsIndex))) {
+ --lhsIndex;
continue;
}
- if (!Character.isDigit(rhs.charAt(bIndex))) {
- --bIndex;
+ if (!Character.isDigit(rhs.charAt(rhsIndex))) {
+ --rhsIndex;
continue;
}
- if (lhs.charAt(aIndex) != rhs.charAt(bIndex)) {
- return false;
+ if (lhs.charAt(lhsIndex) != rhs.charAt(rhsIndex)) {
+ break;
}
- --aIndex;
- --bIndex;
+ --lhsIndex;
+ --rhsIndex;
++matchedDigits;
}
diff --git a/java/com/android/dialer/interactions/PhoneNumberInteraction.java b/java/com/android/dialer/interactions/PhoneNumberInteraction.java
index ef468a9..39781cf 100644
--- a/java/com/android/dialer/interactions/PhoneNumberInteraction.java
+++ b/java/com/android/dialer/interactions/PhoneNumberInteraction.java
@@ -15,7 +15,6 @@
*/
package com.android.dialer.interactions;
-import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
@@ -28,7 +27,6 @@
import android.content.Intent;
import android.content.Loader;
import android.content.Loader.OnLoadCompleteListener;
-import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -42,7 +40,6 @@
import android.support.annotation.IntDef;
import android.support.annotation.VisibleForTesting;
import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -63,10 +60,12 @@
import com.android.dialer.logging.InteractionEvent;
import com.android.dialer.logging.Logger;
import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.PermissionsUtil;
import com.android.dialer.util.TransactionSafeActivity;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -221,20 +220,27 @@
// It's possible for a shortcut to have been created, and then permissions revoked. To avoid a
// crash when the user tries to use such a shortcut, check for this condition and ask the user
// for the permission.
- if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.CALL_PHONE)
- != PackageManager.PERMISSION_GRANTED) {
- LogUtil.i("PhoneNumberInteraction.startInteraction", "No phone permissions");
+ String[] deniedPhonePermissions =
+ PermissionsUtil.getPermissionsCurrentlyDenied(
+ mContext, PermissionsUtil.allPhoneGroupPermissionsUsedInDialer);
+ if (deniedPhonePermissions.length > 0) {
+ LogUtil.i(
+ "PhoneNumberInteraction.startInteraction",
+ "Need phone permissions: " + Arrays.toString(deniedPhonePermissions));
ActivityCompat.requestPermissions(
- (Activity) mContext, new String[] {Manifest.permission.CALL_PHONE}, REQUEST_CALL_PHONE);
+ (Activity) mContext, deniedPhonePermissions, REQUEST_CALL_PHONE);
return;
}
- if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_CONTACTS)
- != PackageManager.PERMISSION_GRANTED) {
- LogUtil.i("PhoneNumberInteraction.startInteraction", "No contact permissions");
+
+ String[] deniedContactsPermissions =
+ PermissionsUtil.getPermissionsCurrentlyDenied(
+ mContext, PermissionsUtil.allContactsGroupPermissionsUsedInDialer);
+ if (deniedContactsPermissions.length > 0) {
+ LogUtil.i(
+ "PhoneNumberInteraction.startInteraction",
+ "Need contact permissions: " + Arrays.toString(deniedContactsPermissions));
ActivityCompat.requestPermissions(
- (Activity) mContext,
- new String[] {Manifest.permission.READ_CONTACTS},
- REQUEST_READ_CONTACTS);
+ (Activity) mContext, deniedContactsPermissions, REQUEST_READ_CONTACTS);
return;
}
diff --git a/java/com/android/dialer/lettertile/AndroidManifest.xml b/java/com/android/dialer/lettertile/AndroidManifest.xml
new file mode 100644
index 0000000..dce6806
--- /dev/null
+++ b/java/com/android/dialer/lettertile/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<!--
+ ~ 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
+ -->
+<manifest
+ package="com.android.dialer.lettertile">
+</manifest>
diff --git a/java/com/android/contacts/common/lettertiles/LetterTileDrawable.java b/java/com/android/dialer/lettertile/LetterTileDrawable.java
similarity index 98%
rename from java/com/android/contacts/common/lettertiles/LetterTileDrawable.java
rename to java/com/android/dialer/lettertile/LetterTileDrawable.java
index 73809c4..c8b75c5 100644
--- a/java/com/android/contacts/common/lettertiles/LetterTileDrawable.java
+++ b/java/com/android/dialer/lettertile/LetterTileDrawable.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.common.lettertiles;
+package com.android.dialer.lettertile;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -33,7 +33,6 @@
import android.support.annotation.Nullable;
import android.telecom.TelecomManager;
import android.text.TextUtils;
-import com.android.contacts.common.R;
import com.android.dialer.common.Assert;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -55,6 +54,7 @@
/** Contact type constants */
public static final int TYPE_PERSON = 1;
+
public static final int TYPE_BUSINESS = 2;
public static final int TYPE_VOICEMAIL = 3;
/**
@@ -62,6 +62,7 @@
* situations where a contact is anonymous.
*/
public static final int TYPE_GENERIC_AVATAR = 4;
+
public static final int TYPE_SPAM = 5;
public static final int TYPE_CONFERENCE = 6;
@ContactType public static final int TYPE_DEFAULT = TYPE_PERSON;
@@ -128,8 +129,7 @@
mDefaultSpamAvatar = res.getDrawable(R.drawable.quantum_ic_report_vd_theme_24, null);
mDefaultConferenceAvatar = res.getDrawable(R.drawable.quantum_ic_group_vd_theme_24, null);
- mPaint.setTypeface(
- Typeface.create(res.getString(R.string.letter_tile_letter_font_family), Typeface.NORMAL));
+ mPaint.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL));
mPaint.setTextAlign(Align.CENTER);
mPaint.setAntiAlias(true);
mPaint.setFilterBitmap(true);
diff --git a/java/com/android/dialer/lettertile/res/values/colors.xml b/java/com/android/dialer/lettertile/res/values/colors.xml
new file mode 100644
index 0000000..406b490
--- /dev/null
+++ b/java/com/android/dialer/lettertile/res/values/colors.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<resources>
+ <array name="letter_tile_colors">
+ <item>#DB4437</item>
+ <item>#E91E63</item>
+ <item>#9C27B0</item>
+ <item>#673AB7</item>
+ <item>#3F51B5</item>
+ <item>#4285F4</item>
+ <item>#039BE5</item>
+ <item>#0097A7</item>
+ <item>#009688</item>
+ <item>#0F9D58</item>
+ <item>#689F38</item>
+ <item>#EF6C00</item>
+ <item>#FF5722</item>
+ <item>#757575</item>
+ </array>
+
+ <color name="spam_contact_background">#A52714</color>
+
+ <color name="letter_tile_default_color">#cccccc</color>
+
+ <color name="letter_tile_font_color">#ffffff</color>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/lettertile/res/values/dimens.xml b/java/com/android/dialer/lettertile/res/values/dimens.xml
new file mode 100644
index 0000000..c804431
--- /dev/null
+++ b/java/com/android/dialer/lettertile/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<resources>
+ <!-- Dimensions for contact letter tiles -->
+ <item name="letter_to_tile_ratio" type="dimen">67%</item>
+</resources>
\ No newline at end of file
diff --git a/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java b/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java
index 5c7a28c..8bd8335 100644
--- a/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java
+++ b/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java
@@ -27,6 +27,7 @@
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.support.v4.os.UserManagerCompat;
+import com.android.dialer.common.LogUtil;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -58,6 +59,16 @@
private static final String LOG_DIRECTORY = "persistent_log";
private static final String NEXT_FILE_INDEX_PREFIX = "persistent_long_next_file_index_";
+ private static final byte[] ENTRY_PREFIX = {'P'};
+ private static final byte[] ENTRY_POSTFIX = {'L'};
+
+ private static class LogCorruptionException extends Exception {
+
+ public LogCorruptionException(String message) {
+ super(message);
+ }
+ };
+
private File logDirectory;
private final String subfolder;
private final int fileSizeLimit;
@@ -106,8 +117,10 @@
try (DataOutputStream outputStream =
new DataOutputStream(new FileOutputStream(outputFile, true))) {
for (byte[] log : logs) {
+ outputStream.write(ENTRY_PREFIX);
outputStream.writeInt(log.length);
outputStream.write(log);
+ outputStream.write(ENTRY_POSTFIX);
}
outputStream.close();
if (outputFile.length() > fileSizeLimit) {
@@ -116,6 +129,21 @@
}
}
+ void writeRawLogsForTest(byte[] data) throws IOException {
+ if (outputFile == null) {
+ selectNextFileToWrite();
+ }
+ outputFile.createNewFile();
+ try (DataOutputStream outputStream =
+ new DataOutputStream(new FileOutputStream(outputFile, true))) {
+ outputStream.write(data);
+ outputStream.close();
+ if (outputFile.length() > fileSizeLimit) {
+ selectNextFileToWrite();
+ }
+ }
+ }
+
/** Concatenate all log files in chronicle order and return a byte array. */
@WorkerThread
@NonNull
@@ -149,10 +177,21 @@
logs.add(log);
log = readLog(input);
}
+ } catch (LogCorruptionException e) {
+ LogUtil.e("PersistentLogFileHandler.getLogs", "logs corrupted, deleting", e);
+ deleteLogs();
+ return new ArrayList<>();
}
return logs;
}
+ private void deleteLogs() throws IOException {
+ for (File file : getLogFiles()) {
+ file.delete();
+ }
+ selectNextFileToWrite();
+ }
+
@WorkerThread
private void selectNextFileToWrite() throws IOException {
File[] files = getLogFiles();
@@ -186,10 +225,28 @@
@Nullable
@WorkerThread
- private static byte[] readLog(DataInputStream inputStream) throws IOException {
+ private byte[] readLog(DataInputStream inputStream) throws IOException, LogCorruptionException {
try {
- byte[] data = new byte[inputStream.readInt()];
+ byte[] prefix = new byte[ENTRY_PREFIX.length];
+ if (inputStream.read(prefix) == -1) {
+ // EOF
+ return null;
+ }
+ if (!Arrays.equals(prefix, ENTRY_PREFIX)) {
+ throw new LogCorruptionException("entry prefix mismatch");
+ }
+ int dataLength = inputStream.readInt();
+ if (dataLength > fileSizeLimit) {
+ throw new LogCorruptionException("data length over max size");
+ }
+ byte[] data = new byte[dataLength];
inputStream.read(data);
+
+ byte[] postfix = new byte[ENTRY_POSTFIX.length];
+ inputStream.read(postfix);
+ if (!Arrays.equals(postfix, ENTRY_POSTFIX)) {
+ throw new LogCorruptionException("entry postfix mismatch");
+ }
return data;
} catch (EOFException e) {
return null;
diff --git a/java/com/android/dialer/persistentlog/PersistentLogger.java b/java/com/android/dialer/persistentlog/PersistentLogger.java
index 7d82ec1..847625e 100644
--- a/java/com/android/dialer/persistentlog/PersistentLogger.java
+++ b/java/com/android/dialer/persistentlog/PersistentLogger.java
@@ -110,6 +110,16 @@
loggerThreadHandler.sendEmptyMessageDelayed(MESSAGE_FLUSH, FLUSH_DELAY_MILLIS);
}
+ @VisibleForTesting
+ /** write raw bytes directly to the log file, likely corrupting it. */
+ static void rawLogForTest(byte[] data) {
+ try {
+ fileHandler.writeRawLogsForTest(data);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/** Dump the log as human readable string. Blocks until the dump is finished. */
@NonNull
@WorkerThread
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfo.java b/java/com/android/dialer/phonenumbercache/ContactInfo.java
index aef7374..a620a23 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfo.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfo.java
@@ -20,8 +20,8 @@
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.android.contacts.common.ContactsUtils.UserType;
-import com.android.contacts.common.util.UriUtils;
import com.android.dialer.logging.ContactSource;
+import com.android.dialer.util.UriUtils;
/** Information for a contact as needed by the Call Log. */
public class ContactInfo {
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
index 4fa3147..b680bd5 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
@@ -38,7 +38,6 @@
import com.android.contacts.common.ContactsUtils.UserType;
import com.android.contacts.common.compat.DirectoryCompat;
import com.android.contacts.common.util.Constants;
-import com.android.contacts.common.util.UriUtils;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.logging.ContactSource;
@@ -48,6 +47,7 @@
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.PermissionsUtil;
+import com.android.dialer.util.UriUtils;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONException;
diff --git a/java/com/android/dialer/postcall/PostCall.java b/java/com/android/dialer/postcall/PostCall.java
index 6d9ad01..c4922cd 100644
--- a/java/com/android/dialer/postcall/PostCall.java
+++ b/java/com/android/dialer/postcall/PostCall.java
@@ -79,7 +79,7 @@
LogUtil.sanitizePhoneNumber(getPhoneNumber(activity)),
capabilities);
- boolean isRcsPostCall = capabilities != null && capabilities.supportsPostCall();
+ boolean isRcsPostCall = capabilities != null && capabilities.isPostCallCapable();
String actionText =
isRcsPostCall
? activity.getString(R.string.post_call_add_message)
diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
index d3df02f..4b5cab9 100644
--- a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
+++ b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java
@@ -30,11 +30,11 @@
import android.widget.ImageView;
import android.widget.QuickContactBadge;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.callintent.CallInitiationType.Type;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.Assert;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.searchfragment.common.Projections;
import com.android.dialer.searchfragment.common.QueryBoldingUtil;
import com.android.dialer.searchfragment.common.R;
@@ -91,7 +91,7 @@
numberView.setText(QueryBoldingUtil.getNumberWithQueryBolded(query, secondaryInfo));
setCallToAction(cursor);
- if (shouldShowPhoto(cursor, name)) {
+ if (shouldShowPhoto(cursor)) {
nameOrNumberView.setVisibility(View.VISIBLE);
photo.setVisibility(View.VISIBLE);
String photoUri = cursor.getString(Projections.PHONE_PHOTO_URI);
@@ -109,15 +109,16 @@
}
}
- private boolean shouldShowPhoto(Cursor cursor, String currentName) {
+ private boolean shouldShowPhoto(Cursor cursor) {
int currentPosition = cursor.getPosition();
if (currentPosition == 0) {
return true;
} else {
+ String currentLookupKey = cursor.getString(Projections.PHONE_LOOKUP_KEY);
cursor.moveToPosition(currentPosition - 1);
- String previousName = cursor.getString(Projections.PHONE_DISPLAY_NAME);
+ String previousLookupKey = cursor.getString(Projections.PHONE_LOOKUP_KEY);
cursor.moveToPosition(currentPosition);
- return !currentName.equals(previousName);
+ return !currentLookupKey.equals(previousLookupKey);
}
}
diff --git a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
index b6e5a90..575582e 100644
--- a/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
+++ b/java/com/android/dialer/searchfragment/nearbyplaces/NearbyPlaceViewHolder.java
@@ -24,10 +24,10 @@
import android.view.View;
import android.widget.QuickContactBadge;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.searchfragment.common.Projections;
import com.android.dialer.searchfragment.common.QueryBoldingUtil;
import com.android.dialer.searchfragment.common.R;
diff --git a/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java b/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
new file mode 100644
index 0000000..18a8718
--- /dev/null
+++ b/java/com/android/dialer/searchfragment/remote/RemoteContactViewHolder.java
@@ -0,0 +1,130 @@
+/*
+ * 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.searchfragment.remote;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.QuickContactBadge;
+import android.widget.TextView;
+import com.android.dialer.callintent.CallInitiationType;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.searchfragment.common.Projections;
+import com.android.dialer.searchfragment.common.QueryBoldingUtil;
+import com.android.dialer.searchfragment.common.R;
+import com.android.dialer.telecom.TelecomUtil;
+
+/** ViewHolder for a nearby place row. */
+public final class RemoteContactViewHolder extends RecyclerView.ViewHolder
+ implements View.OnClickListener {
+
+ private final Context context;
+ private final TextView nameView;
+ private final TextView numberView;
+ private final QuickContactBadge photo;
+
+ private String number;
+
+ public RemoteContactViewHolder(View view) {
+ super(view);
+ view.setOnClickListener(this);
+ photo = view.findViewById(R.id.photo);
+ nameView = view.findViewById(R.id.primary);
+ numberView = view.findViewById(R.id.secondary);
+ context = view.getContext();
+ }
+
+ /**
+ * Binds the ViewHolder with a cursor from {@link RemoteContactsCursorLoader} with the data found
+ * at the cursors current position.
+ */
+ public void bind(Cursor cursor, String query) {
+ number = cursor.getString(Projections.PHONE_NUMBER);
+ String name = cursor.getString(Projections.PHONE_DISPLAY_NAME);
+ String label = getLabel(context.getResources(), cursor);
+ String secondaryInfo =
+ TextUtils.isEmpty(label)
+ ? number
+ : context.getString(
+ com.android.contacts.common.R.string.call_subject_type_and_number, label, number);
+
+ nameView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, name));
+ numberView.setText(QueryBoldingUtil.getNameWithQueryBolded(query, secondaryInfo));
+
+ if (shouldShowPhoto(cursor)) {
+ nameView.setVisibility(View.VISIBLE);
+ photo.setVisibility(View.VISIBLE);
+ String photoUri = cursor.getString(Projections.PHONE_PHOTO_URI);
+ ContactPhotoManager.getInstance(context)
+ .loadDialerThumbnailOrPhoto(
+ photo,
+ getContactUri(cursor),
+ cursor.getLong(Projections.PHONE_PHOTO_ID),
+ photoUri == null ? null : Uri.parse(photoUri),
+ name,
+ LetterTileDrawable.TYPE_DEFAULT);
+ } else {
+ nameView.setVisibility(View.GONE);
+ photo.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private boolean shouldShowPhoto(Cursor cursor) {
+ int currentPosition = cursor.getPosition();
+ if (currentPosition == 0) {
+ return true;
+ }
+
+ String currentLookupKey = cursor.getString(Projections.PHONE_LOOKUP_KEY);
+ cursor.moveToPosition(currentPosition - 1);
+ String previousLookupKey = cursor.getString(Projections.PHONE_LOOKUP_KEY);
+ cursor.moveToPosition(currentPosition);
+ return !currentLookupKey.equals(previousLookupKey);
+ }
+
+ // TODO(calderwoodra): unify this into a utility method with CallLogAdapter#getNumberType
+ private static String getLabel(Resources resources, Cursor cursor) {
+ int numberType = cursor.getInt(Projections.PHONE_TYPE);
+ String numberLabel = cursor.getString(Projections.PHONE_LABEL);
+
+ // Returns empty label instead of "custom" if the custom label is empty.
+ if (numberType == Phone.TYPE_CUSTOM && TextUtils.isEmpty(numberLabel)) {
+ return "";
+ }
+ return (String) Phone.getTypeLabel(resources, numberType, numberLabel);
+ }
+
+ private static Uri getContactUri(Cursor cursor) {
+ long contactId = cursor.getLong(Projections.PHONE_ID);
+ String lookupKey = cursor.getString(Projections.PHONE_LOOKUP_KEY);
+ return ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
+ }
+
+ @Override
+ public void onClick(View v) {
+ TelecomUtil.placeCall(
+ context, new CallIntentBuilder(number, CallInitiationType.Type.REGULAR_SEARCH).build());
+ }
+}
diff --git a/java/com/android/dialer/searchfragment/remote/RemoteContactsCursorLoader.java b/java/com/android/dialer/searchfragment/remote/RemoteContactsCursorLoader.java
new file mode 100644
index 0000000..d4b1963
--- /dev/null
+++ b/java/com/android/dialer/searchfragment/remote/RemoteContactsCursorLoader.java
@@ -0,0 +1,71 @@
+/*
+ * 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.searchfragment.remote;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.net.Uri;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.support.annotation.VisibleForTesting;
+import com.android.dialer.searchfragment.common.Projections;
+import com.android.dialer.searchfragment.remote.RemoteDirectoriesCursorLoader.Directory;
+
+/** Cursor loader to load extended contacts on device. */
+final class RemoteContactsCursorLoader extends CursorLoader {
+
+ private static final Uri ENTERPRISE_CONTENT_FILTER_URI =
+ Uri.withAppendedPath(Phone.CONTENT_URI, "filter_enterprise");
+
+ private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE = "length(" + Phone.NUMBER + ") < 1000";
+ private static final String MAX_RESULTS = "20";
+
+ private final Directory directory;
+
+ RemoteContactsCursorLoader(Context context, String query, Directory directory) {
+ super(
+ context,
+ getContentFilterUri(query, directory.id),
+ Projections.PHONE_PROJECTION,
+ IGNORE_NUMBER_TOO_LONG_CLAUSE,
+ null,
+ Phone.SORT_KEY_PRIMARY);
+ this.directory = directory;
+ }
+
+ @VisibleForTesting
+ static Uri getContentFilterUri(String query, int directoryId) {
+ Uri baseUri = Phone.CONTENT_FILTER_URI;
+ if (VERSION.SDK_INT >= VERSION_CODES.N) {
+ baseUri = ENTERPRISE_CONTENT_FILTER_URI;
+ }
+
+ return baseUri
+ .buildUpon()
+ .appendPath(query)
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId))
+ .appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true")
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, MAX_RESULTS)
+ .build();
+ }
+
+ public Directory getDirectory() {
+ return directory;
+ }
+}
diff --git a/java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java b/java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java
new file mode 100644
index 0000000..0a4ca0e
--- /dev/null
+++ b/java/com/android/dialer/searchfragment/remote/RemoteDirectoriesCursorLoader.java
@@ -0,0 +1,117 @@
+/*
+
+* 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.searchfragment.remote;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.provider.ContactsContract;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import com.android.dialer.common.LogUtil;
+
+/** CursorLoader to load the list of remote directories on the device. */
+public final class RemoteDirectoriesCursorLoader extends CursorLoader {
+
+ /** Positions of columns in {@code PROJECTIONS}. */
+ private static final int ID = 0;
+
+ private static final int PACKAGE_NAME = 1;
+ private static final int TYPE_RESOURCE_ID = 2;
+ private static final int DISPLAY_NAME = 3;
+ private static final int PHOTO_SUPPORT = 4;
+
+ @VisibleForTesting
+ static final String[] PROJECTION = {
+ ContactsContract.Directory._ID,
+ ContactsContract.Directory.PACKAGE_NAME,
+ ContactsContract.Directory.TYPE_RESOURCE_ID,
+ ContactsContract.Directory.DISPLAY_NAME,
+ ContactsContract.Directory.PHOTO_SUPPORT,
+ };
+
+ RemoteDirectoriesCursorLoader(Context context) {
+ super(context, getContentUri(), PROJECTION, null, null, ContactsContract.Directory._ID);
+ }
+
+ /**
+ * Returns the type of directory as a String (e.g. "Corporate Directory"). Null if the directory
+ * type cannot be found.
+ */
+ @Nullable
+ private static String getDirectoryType(Context context, Cursor cursor) {
+ String packageName = cursor.getString(PACKAGE_NAME);
+ int typeResourceId = cursor.getInt(TYPE_RESOURCE_ID);
+ if (TextUtils.isEmpty(packageName) || typeResourceId == 0) {
+ return null;
+ }
+
+ try {
+ return context
+ .getPackageManager()
+ .getResourcesForApplication(packageName)
+ .getString(typeResourceId);
+ } catch (NameNotFoundException e) {
+ LogUtil.e(
+ "ContactEntryListAdapter.loadInBackground",
+ "cannot obtain directory type from package: %s",
+ packageName);
+ return null;
+ }
+ }
+
+ /** @return current cursor row represented as a {@link Directory}. */
+ public static Directory readDirectory(Context context, Cursor cursor) {
+ return new Directory(
+ cursor.getInt(ID),
+ cursor.getString(DISPLAY_NAME),
+ getDirectoryType(context, cursor),
+ cursor.getInt(PHOTO_SUPPORT) != 0);
+ }
+
+ private static Uri getContentUri() {
+ return VERSION.SDK_INT >= VERSION_CODES.N
+ ? ContactsContract.Directory.ENTERPRISE_CONTENT_URI
+ : ContactsContract.Directory.CONTENT_URI;
+ }
+
+ /** POJO representing the results returned from {@link RemoteDirectoriesCursorLoader}. */
+ public static class Directory {
+
+ public final int id;
+ // TODO(calderwoodra): investigate which of these fields will be used as the display name and
+ // update the fields and javadoc accordingly.
+ /** An optional name that can be used in the UI to represent the directory. */
+ @Nullable public final String name;
+
+ @Nullable public final String type;
+ public final boolean supportsPhotos;
+
+ public Directory(int id, String name, @Nullable String type, boolean supportsPhotos) {
+ this.id = id;
+ this.name = name;
+ this.type = type;
+ this.supportsPhotos = supportsPhotos;
+ }
+ }
+}
diff --git a/java/com/android/dialer/shortcuts/IconFactory.java b/java/com/android/dialer/shortcuts/IconFactory.java
index 4ec964c..7aad112 100644
--- a/java/com/android/dialer/shortcuts/IconFactory.java
+++ b/java/com/android/dialer/shortcuts/IconFactory.java
@@ -33,8 +33,8 @@
import android.support.annotation.WorkerThread;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.common.Assert;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.util.DrawableConverter;
import java.io.InputStream;
diff --git a/java/com/android/dialer/shortcuts/ShortcutRefresher.java b/java/com/android/dialer/shortcuts/ShortcutRefresher.java
index 120382d..496f3f0 100644
--- a/java/com/android/dialer/shortcuts/ShortcutRefresher.java
+++ b/java/com/android/dialer/shortcuts/ShortcutRefresher.java
@@ -20,21 +20,17 @@
import android.os.Build;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
import com.android.contacts.common.list.ContactEntry;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
-import com.android.dialer.common.concurrent.AsyncTaskExecutor;
-import com.android.dialer.common.concurrent.AsyncTaskExecutors;
-import com.android.dialer.common.concurrent.FallibleAsyncTask;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.common.concurrent.DialerExecutors;
import java.util.ArrayList;
import java.util.List;
/** Refreshes launcher shortcuts from UI components using provided list of contacts. */
public final class ShortcutRefresher {
- private static final AsyncTaskExecutor EXECUTOR = AsyncTaskExecutors.createThreadPoolExecutor();
-
/** Asynchronously updates launcher shortcuts using the provided list of contacts. */
@MainThread
public static void refresh(@NonNull Context context, List<ContactEntry> contacts) {
@@ -49,36 +45,27 @@
return;
}
- //noinspection unchecked
- EXECUTOR.submit(Task.ID, new Task(context), new ArrayList<>(contacts));
+ DialerExecutors.createNonUiTaskBuilder(new RefreshWorker(context))
+ .build()
+ .executeSerial(new ArrayList<>(contacts));
}
- private static final class Task extends FallibleAsyncTask<List<ContactEntry>, Void, Void> {
- private static final String ID = "ShortcutRefresher.Task";
-
+ private static final class RefreshWorker implements Worker<List<ContactEntry>, Void> {
private final Context context;
- Task(Context context) {
+ RefreshWorker(Context context) {
this.context = context;
}
- /**
- * @param params array containing exactly one element, the list of contacts from favorites
- * tiles, ordered in tile order.
- */
- @SafeVarargs
@Override
- @NonNull
- @WorkerThread
- protected final Void doInBackgroundFallible(List<ContactEntry>... params) {
- Assert.isWorkerThread();
+ public Void doInBackground(List<ContactEntry> contacts) {
LogUtil.enterBlock("ShortcutRefresher.Task.doInBackground");
// Only dynamic shortcuts are maintained from UI components. Pinned shortcuts are maintained
// by the job scheduler. This is because a pinned contact may not necessarily still be in the
// favorites tiles, so refreshing it would require an additional database query. We don't want
// to incur the cost of that extra database query every time the favorites tiles change.
- new DynamicShortcuts(context, new IconFactory(context)).refresh(params[0]); // Blocking
+ new DynamicShortcuts(context, new IconFactory(context)).refresh(contacts); // Blocking
return null;
}
diff --git a/java/com/android/dialer/theme/res/values/strings.xml b/java/com/android/dialer/theme/res/values/strings.xml
index af61d35..74cabad 100644
--- a/java/com/android/dialer/theme/res/values/strings.xml
+++ b/java/com/android/dialer/theme/res/values/strings.xml
@@ -30,9 +30,6 @@
used in the Launcher icon. -->
<string name="launcherActivityLabel">Phone</string>
- <!-- Text presented to the user explaining that we have enabled the camera permission automatically -->
- <string name="camera_privacy_text">Camera permission enabled</string>
-
<!-- text on a button, Video call, as in to place a video call. -->
<string name="video_call">Video call</string>
diff --git a/java/com/android/dialer/util/PermissionsUtil.java b/java/com/android/dialer/util/PermissionsUtil.java
index 3482831..cb97368 100644
--- a/java/com/android/dialer/util/PermissionsUtil.java
+++ b/java/com/android/dialer/util/PermissionsUtil.java
@@ -38,6 +38,7 @@
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
+import android.widget.Toast;
import com.android.dialer.common.LogUtil;
import java.util.ArrayList;
import java.util.Arrays;
@@ -47,6 +48,7 @@
/** Utility class to help with runtime permissions. */
public class PermissionsUtil {
+ private static final String PREFERENCE_CAMERA_ALLOWED_BY_USER = "camera_allowed_by_user";
private static final String PERMISSION_PREFERENCE = "dialer_permissions";
private static final String CEQUINT_PERMISSION = "com.cequint.ecid.CALLER_ID_LOOKUP";
@@ -207,4 +209,28 @@
}
return permissionsCurrentlyDenied.toArray(new String[permissionsCurrentlyDenied.size()]);
}
+
+ /**
+ * Since we are granted the camera permission automatically as a first-party app, we need to show
+ * a toast to let users know the permission was granted for privacy reasons.
+ *
+ * @return true if we've already shown the camera privacy toast.
+ */
+ public static boolean hasCameraPrivacyToastShown(@NonNull Context context) {
+ return DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context)
+ .getBoolean(PREFERENCE_CAMERA_ALLOWED_BY_USER, false);
+ }
+
+ public static void showCameraPermissionToast(@NonNull Context context) {
+ Toast.makeText(context, context.getString(R.string.camera_privacy_text), Toast.LENGTH_LONG)
+ .show();
+ setCameraPrivacyToastShown(context);
+ }
+
+ public static void setCameraPrivacyToastShown(@NonNull Context context) {
+ DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context)
+ .edit()
+ .putBoolean(PREFERENCE_CAMERA_ALLOWED_BY_USER, true)
+ .apply();
+ }
}
diff --git a/java/com/android/contacts/common/util/UriUtils.java b/java/com/android/dialer/util/UriUtils.java
similarity index 94%
rename from java/com/android/contacts/common/util/UriUtils.java
rename to java/com/android/dialer/util/UriUtils.java
index 4690942..c4308a8 100644
--- a/java/com/android/contacts/common/util/UriUtils.java
+++ b/java/com/android/dialer/util/UriUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.common.util;
+package com.android.dialer.util;
import android.net.Uri;
import android.provider.ContactsContract;
@@ -23,6 +23,8 @@
/** Utility methods for dealing with URIs. */
public class UriUtils {
+ private static final String LOOKUP_URI_ENCODED = "encoded";
+
/** Static helper, not instantiable. */
private UriUtils() {}
@@ -58,7 +60,7 @@
if (lastPathSegment == null) {
return false;
}
- return lastPathSegment.equals(Constants.LOOKUP_URI_ENCODED);
+ return lastPathSegment.equals(LOOKUP_URI_ENCODED);
}
/**
diff --git a/java/com/android/dialer/util/res/values/strings.xml b/java/com/android/dialer/util/res/values/strings.xml
index 43ea6e3..a4d944c 100644
--- a/java/com/android/dialer/util/res/values/strings.xml
+++ b/java/com/android/dialer/util/res/values/strings.xml
@@ -39,4 +39,6 @@
<!-- Text for button which indicates that the user wants to proceed with an action. -->
<string name="dialog_continue">Continue</string>
+ <!-- Text presented to the user explaining that we have enabled the camera permission automatically [CHAR LIMIT=NONE] -->
+ <string name="camera_privacy_text">Camera permission enabled</string>
</resources>
diff --git a/java/com/android/incallui/CallButtonPresenter.java b/java/com/android/incallui/CallButtonPresenter.java
index dbb6a1c..d4b77ad 100644
--- a/java/com/android/incallui/CallButtonPresenter.java
+++ b/java/com/android/incallui/CallButtonPresenter.java
@@ -414,7 +414,7 @@
final boolean showMute = call.can(android.telecom.Call.Details.CAPABILITY_MUTE);
final boolean hasCameraPermission =
- isVideo && VideoUtils.hasCameraPermissionAndAllowedByUser(mContext);
+ isVideo && VideoUtils.hasCameraPermissionAndShownPrivacyToast(mContext);
// Disabling local video doesn't seem to work when dialing. See b/30256571.
final boolean showPauseVideo =
isVideo
diff --git a/java/com/android/incallui/CallCardPresenter.java b/java/com/android/incallui/CallCardPresenter.java
index 67b9177..3906832 100644
--- a/java/com/android/incallui/CallCardPresenter.java
+++ b/java/com/android/incallui/CallCardPresenter.java
@@ -60,6 +60,7 @@
import com.android.incallui.InCallPresenter.IncomingCallListener;
import com.android.incallui.call.CallList;
import com.android.incallui.call.DialerCall;
+import com.android.incallui.call.DialerCall.State;
import com.android.incallui.call.DialerCallListener;
import com.android.incallui.calllocation.CallLocation;
import com.android.incallui.calllocation.CallLocationComponent;
@@ -67,6 +68,7 @@
import com.android.incallui.incall.protocol.InCallScreen;
import com.android.incallui.incall.protocol.InCallScreenDelegate;
import com.android.incallui.incall.protocol.PrimaryCallState;
+import com.android.incallui.incall.protocol.PrimaryCallState.ButtonState;
import com.android.incallui.incall.protocol.PrimaryInfo;
import com.android.incallui.incall.protocol.SecondaryInfo;
import com.android.incallui.videotech.utils.SessionModificationState;
@@ -472,7 +474,8 @@
CallerInfoUtils.isVoiceMailNumber(mContext, mPrimary),
mPrimary.isRemotelyHeld(),
isBusiness,
- supports2ndCallOnHold()));
+ supports2ndCallOnHold(),
+ getSwapToSecondaryButtonState()));
InCallActivity activity =
(InCallActivity) (mInCallScreen.getInCallScreenFragment().getActivity());
@@ -482,6 +485,16 @@
}
}
+ private @ButtonState int getSwapToSecondaryButtonState() {
+ if (mSecondary == null) {
+ return ButtonState.NOT_SUPPORT;
+ }
+ if (mPrimary.getState() == State.ACTIVE) {
+ return ButtonState.ENABLED;
+ }
+ return ButtonState.DISABLED;
+ }
+
/** Only show the conference call button if we can manage the conference. */
private void maybeShowManageConferenceCallButton() {
getUi().showManageConferenceCallButton(shouldShowManageConference());
diff --git a/java/com/android/incallui/ConferenceManagerFragment.java b/java/com/android/incallui/ConferenceManagerFragment.java
index cef8a38..bd6cb85 100644
--- a/java/com/android/incallui/ConferenceManagerFragment.java
+++ b/java/com/android/incallui/ConferenceManagerFragment.java
@@ -21,7 +21,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import com.android.contacts.common.ContactPhotoManager;
+import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.ScreenEvent;
import com.android.incallui.ConferenceManagerPresenter.ConferenceManagerUi;
diff --git a/java/com/android/incallui/ConferenceParticipantListAdapter.java b/java/com/android/incallui/ConferenceParticipantListAdapter.java
index 712bdef..70cdf24 100644
--- a/java/com/android/incallui/ConferenceParticipantListAdapter.java
+++ b/java/com/android/incallui/ConferenceParticipantListAdapter.java
@@ -31,12 +31,12 @@
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
-import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
import com.android.incallui.ContactInfoCache.ContactCacheEntry;
import com.android.incallui.call.CallList;
import com.android.incallui.call.DialerCall;
diff --git a/java/com/android/incallui/ExternalCallNotifier.java b/java/com/android/incallui/ExternalCallNotifier.java
index f01a294..ed3c918 100644
--- a/java/com/android/incallui/ExternalCallNotifier.java
+++ b/java/com/android/incallui/ExternalCallNotifier.java
@@ -40,8 +40,8 @@
import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.compat.CallCompat;
import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.BitmapUtil;
import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.dialer.contactphoto.BitmapUtil;
import com.android.dialer.notification.NotificationChannelId;
import com.android.incallui.call.DialerCall;
import com.android.incallui.call.DialerCallDelegate;
diff --git a/java/com/android/incallui/InCallActivityCommon.java b/java/com/android/incallui/InCallActivityCommon.java
index 3a264be..14531e0 100644
--- a/java/com/android/incallui/InCallActivityCommon.java
+++ b/java/com/android/incallui/InCallActivityCommon.java
@@ -21,6 +21,7 @@
import android.app.ActivityManager.TaskDescription;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.KeyguardManager;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
@@ -105,6 +106,8 @@
private boolean animateDialpadOnShow;
private String dtmfTextToPreopulate;
@DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
+ // If activity is going to be recreated. This is usually happening in {@link onNewIntent}.
+ private boolean isRecreating;
private final SelectPhoneAccountListener selectAccountListener =
new SelectPhoneAccountListener() {
@@ -209,7 +212,8 @@
}
});
- if (icicle != null) {
+ // Don't override the value if show dialpad request is true in intent extras.
+ if (icicle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
// If the dialpad was shown before, set variables indicating it should be shown and
// populated with the previous DTMF text. The dialpad is actually shown and populated
// in onResume() to ensure the hosting fragment has been inflated and is ready to receive it.
@@ -319,6 +323,18 @@
}
public void onStop() {
+ // Disconnects call waiting for account when activity is hidden e.g. user press home button.
+ // This is necessary otherwise the pending call will stuck on account choose and no new call
+ // will be able to create. See b/63600434 for more details.
+ // Skip this on locked screen since the activity may go over life cycle and start again.
+ if (!isRecreating
+ && !inCallActivity.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
+ DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
+ if (waitingForAccountCall != null) {
+ waitingForAccountCall.disconnect();
+ }
+ }
+
enableInCallOrientationEventListener(false);
InCallPresenter.getInstance().updateIsChangingConfigurations();
InCallPresenter.getInstance().onActivityStopped();
@@ -331,6 +347,7 @@
void onNewIntent(Intent intent, boolean isRecreating) {
LogUtil.i("InCallActivityCommon.onNewIntent", "");
+ this.isRecreating = isRecreating;
// We're being re-launched with a new Intent. Since it's possible for a
// single InCallActivity instance to persist indefinitely (even if we
diff --git a/java/com/android/incallui/ReturnToCallController.java b/java/com/android/incallui/ReturnToCallController.java
index 33154c5..978b140 100644
--- a/java/com/android/incallui/ReturnToCallController.java
+++ b/java/com/android/incallui/ReturnToCallController.java
@@ -134,11 +134,13 @@
@Override
public void onDisconnect(DialerCall call) {
- if (bubble != null && bubble.isVisible()) {
+ boolean hasAnotherCall = CallList.getInstance().getActiveOrBackgroundCall() != null;
+ if (bubble != null
+ && bubble.isVisible()
+ && (!TelecomUtil.isInCall(context) || hasAnotherCall)) {
bubble.showText(context.getText(R.string.incall_call_ended));
}
-
- if (!TelecomUtil.isInCall(context)) {
+ if (!hasAnotherCall) {
hide();
}
}
diff --git a/java/com/android/incallui/StatusBarNotifier.java b/java/com/android/incallui/StatusBarNotifier.java
index 53017a1..03e119e 100644
--- a/java/com/android/incallui/StatusBarNotifier.java
+++ b/java/com/android/incallui/StatusBarNotifier.java
@@ -60,15 +60,15 @@
import android.text.style.ForegroundColorSpan;
import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.ContactsUtils.UserType;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
-import com.android.contacts.common.lettertiles.LetterTileDrawable.ContactType;
import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.BitmapUtil;
import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.configprovider.ConfigProviderBindings;
+import com.android.dialer.contactphoto.BitmapUtil;
import com.android.dialer.enrichedcall.EnrichedCallManager;
import com.android.dialer.enrichedcall.Session;
+import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.lettertile.LetterTileDrawable.ContactType;
import com.android.dialer.multimedia.MultimediaData;
import com.android.dialer.notification.NotificationChannelId;
import com.android.dialer.oem.MotorolaUtils;
diff --git a/java/com/android/incallui/VideoCallPresenter.java b/java/com/android/incallui/VideoCallPresenter.java
index 70f95e0..233b2b5 100644
--- a/java/com/android/incallui/VideoCallPresenter.java
+++ b/java/com/android/incallui/VideoCallPresenter.java
@@ -30,6 +30,7 @@
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.configprovider.ConfigProviderBindings;
+import com.android.dialer.util.PermissionsUtil;
import com.android.incallui.InCallPresenter.InCallDetailsListener;
import com.android.incallui.InCallPresenter.InCallOrientationListener;
import com.android.incallui.InCallPresenter.InCallStateListener;
@@ -186,7 +187,7 @@
*/
public static boolean showOutgoingVideo(
Context context, int videoState, int sessionModificationState) {
- if (!VideoUtils.hasCameraPermissionAndAllowedByUser(context)) {
+ if (!VideoUtils.hasCameraPermissionAndShownPrivacyToast(context)) {
LogUtil.i("VideoCallPresenter.showOutgoingVideo", "Camera permission is disabled by user.");
return false;
}
@@ -421,7 +422,7 @@
@Override
public void onCameraPermissionGranted() {
LogUtil.i("VideoCallPresenter.onCameraPermissionGranted", "");
- VideoUtils.setCameraAllowedByUser(mContext);
+ PermissionsUtil.setCameraPrivacyToastShown(mContext);
enableCamera(mPrimaryCall.getVideoCall(), isCameraRequired());
showVideoUi(
mPrimaryCall.getVideoState(),
@@ -839,7 +840,7 @@
return;
}
- boolean hasCameraPermission = VideoUtils.hasCameraPermissionAndAllowedByUser(mContext);
+ boolean hasCameraPermission = VideoUtils.hasCameraPermissionAndShownPrivacyToast(mContext);
if (!hasCameraPermission) {
videoCall.setCamera(null);
mPreviewSurfaceState = PreviewSurfaceState.NONE;
@@ -1081,22 +1082,23 @@
}
@Override
- public boolean shouldShowCameraPermissionDialog() {
+ public boolean shouldShowCameraPermissionToast() {
if (mPrimaryCall == null) {
- LogUtil.i("VideoCallPresenter.shouldShowCameraPermissionDialog", "null call");
+ LogUtil.i("VideoCallPresenter.shouldShowCameraPermissionToast", "null call");
return false;
}
if (mPrimaryCall.didShowCameraPermission()) {
LogUtil.i(
- "VideoCallPresenter.shouldShowCameraPermissionDialog", "already shown for this call");
+ "VideoCallPresenter.shouldShowCameraPermissionToast", "already shown for this call");
return false;
}
if (!ConfigProviderBindings.get(mContext)
.getBoolean("camera_permission_dialog_allowed", true)) {
- LogUtil.i("VideoCallPresenter.shouldShowCameraPermissionDialog", "disabled by config");
+ LogUtil.i("VideoCallPresenter.shouldShowCameraPermissionToast", "disabled by config");
return false;
}
- return !VideoUtils.hasCameraPermission(mContext) || !VideoUtils.isCameraAllowedByUser(mContext);
+ return !VideoUtils.hasCameraPermission(mContext)
+ || !PermissionsUtil.hasCameraPrivacyToastShown(mContext);
}
@Override
diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java
index 4431053..b5dd117 100644
--- a/java/com/android/incallui/answer/impl/AnswerFragment.java
+++ b/java/com/android/incallui/answer/impl/AnswerFragment.java
@@ -718,7 +718,7 @@
}
view.setSystemUiVisibility(flags);
if (isVideoCall() || isVideoUpgradeRequest()) {
- if (VideoUtils.hasCameraPermissionAndAllowedByUser(getContext())) {
+ if (VideoUtils.hasCameraPermissionAndShownPrivacyToast(getContext())) {
if (isSelfManagedCamera()) {
answerVideoCallScreen = new SelfManagedAnswerVideoCallScreen(getCallId(), this, view);
} else {
diff --git a/java/com/android/incallui/answer/impl/hint/PawSecretCodeListener.java b/java/com/android/incallui/answer/impl/hint/PawSecretCodeListener.java
index 204c4e1..871d80c 100644
--- a/java/com/android/incallui/answer/impl/hint/PawSecretCodeListener.java
+++ b/java/com/android/incallui/answer/impl/hint/PawSecretCodeListener.java
@@ -24,7 +24,6 @@
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.widget.Toast;
-import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.configprovider.ConfigProviderBindings;
import com.android.dialer.logging.DialerImpression.Type;
@@ -59,7 +58,9 @@
@Override
public void onReceive(Context context, Intent intent) {
String host = intent.getData().getHost();
- Assert.checkState(!TextUtils.isEmpty(host));
+ if (TextUtils.isEmpty(host)) {
+ return;
+ }
String secretCode =
ConfigProviderBindings.get(context).getString(CONFIG_PAW_SECRET_CODE, "729");
if (secretCode == null) {
diff --git a/java/com/android/incallui/commontheme/res/values/styles.xml b/java/com/android/incallui/commontheme/res/values/styles.xml
index c0a745d..a979cc3 100644
--- a/java/com/android/incallui/commontheme/res/values/styles.xml
+++ b/java/com/android/incallui/commontheme/res/values/styles.xml
@@ -17,6 +17,11 @@
<resources>
+ <style name="Dialer.Incall.TextAppearance" parent="android:TextAppearance.Material">
+ <item name="android:textColor">?android:textColorSecondary</item>
+ <item name="android:textSize">18sp</item>
+ </style>
+
<style name="Dialer.Incall.TextAppearance.Large">
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textSize">36sp</item>
@@ -28,11 +33,6 @@
<item name="android:textSize">12sp</item>
</style>
- <style name="Dialer.Incall.TextAppearance" parent="android:TextAppearance.Material">
- <item name="android:textColor">?android:textColorSecondary</item>
- <item name="android:textSize">18sp</item>
- </style>
-
<style name="BottomRowIcon">
<item name="android:layout_height">24dp</item>
<item name="android:layout_width">24dp</item>
diff --git a/java/com/android/incallui/contactgrid/ContactGridManager.java b/java/com/android/incallui/contactgrid/ContactGridManager.java
index 502cc52..a6d7d95 100644
--- a/java/com/android/incallui/contactgrid/ContactGridManager.java
+++ b/java/com/android/incallui/contactgrid/ContactGridManager.java
@@ -30,8 +30,8 @@
import android.widget.TextView;
import android.widget.ViewAnimator;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
-import com.android.contacts.common.lettertiles.LetterTileDrawable;
import com.android.dialer.common.Assert;
+import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.util.DrawableConverter;
import com.android.incallui.incall.protocol.ContactPhotoType;
import com.android.incallui.incall.protocol.PrimaryCallState;
diff --git a/java/com/android/incallui/incall/impl/InCallFragment.java b/java/com/android/incallui/incall/impl/InCallFragment.java
index 54d01e7..1730c80 100644
--- a/java/com/android/incallui/incall/impl/InCallFragment.java
+++ b/java/com/android/incallui/incall/impl/InCallFragment.java
@@ -60,6 +60,7 @@
import com.android.incallui.incall.protocol.InCallScreenDelegate;
import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
import com.android.incallui.incall.protocol.PrimaryCallState;
+import com.android.incallui.incall.protocol.PrimaryCallState.ButtonState;
import com.android.incallui.incall.protocol.PrimaryInfo;
import com.android.incallui.incall.protocol.SecondaryInfo;
import java.util.ArrayList;
@@ -287,10 +288,6 @@
@Override
public void setSecondary(@NonNull SecondaryInfo secondaryInfo) {
LogUtil.i("InCallFragment.setSecondary", secondaryInfo.toString());
- getButtonController(InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY)
- .setEnabled(secondaryInfo.shouldShow);
- getButtonController(InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY)
- .setAllowed(secondaryInfo.shouldShow);
updateButtonStates();
if (!isAdded()) {
@@ -315,6 +312,10 @@
public void setCallState(@NonNull PrimaryCallState primaryCallState) {
LogUtil.i("InCallFragment.setCallState", primaryCallState.toString());
contactGridManager.setCallState(primaryCallState);
+ getButtonController(InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY)
+ .setAllowed(primaryCallState.swapToSecondaryButtonState != ButtonState.NOT_SUPPORT);
+ getButtonController(InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY)
+ .setEnabled(primaryCallState.swapToSecondaryButtonState == ButtonState.ENABLED);
buttonChooser =
ButtonChooserFactory.newButtonChooser(voiceNetworkType, primaryCallState.isWifi, phoneType);
updateButtonStates();
diff --git a/java/com/android/incallui/incall/protocol/PrimaryCallState.java b/java/com/android/incallui/incall/protocol/PrimaryCallState.java
index 26dd388..aac6ff9 100644
--- a/java/com/android/incallui/incall/protocol/PrimaryCallState.java
+++ b/java/com/android/incallui/incall/protocol/PrimaryCallState.java
@@ -17,13 +17,29 @@
package com.android.incallui.incall.protocol;
import android.graphics.drawable.Drawable;
+import android.support.annotation.IntDef;
import android.telecom.DisconnectCause;
import com.android.incallui.call.DialerCall;
import com.android.incallui.videotech.utils.SessionModificationState;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
/** State of the primary call. */
public class PrimaryCallState {
+
+ /**
+ * Button state that will be invisible if not supported, visible but invalid if disabled, or
+ * visible if enabled.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ButtonState.NOT_SUPPORT, ButtonState.DISABLED, ButtonState.ENABLED})
+ public @interface ButtonState {
+ int NOT_SUPPORT = 0;
+ int DISABLED = 1;
+ int ENABLED = 2;
+ }
+
public final int state;
public final boolean isVideoCall;
@SessionModificationState public final int sessionModificationState;
@@ -45,6 +61,7 @@
public final boolean isRemotelyHeld;
public final boolean isBusinessNumber;
public final boolean supportsCallOnHold;
+ public final @ButtonState int swapToSecondaryButtonState;
// TODO: Convert to autovalue. b/34502119
public static PrimaryCallState createEmptyPrimaryCallState() {
@@ -69,7 +86,8 @@
false /* isVoiceMailNumber */,
false /* isRemotelyHeld */,
false /* isBusinessNumber */,
- true /* supportsCallOnHold */);
+ true /* supportsCallOnHold */,
+ ButtonState.NOT_SUPPORT /* swapToSecondaryButtonState */);
}
public PrimaryCallState(
@@ -93,7 +111,8 @@
boolean isVoiceMailNumber,
boolean isRemotelyHeld,
boolean isBusinessNumber,
- boolean supportsCallOnHold) {
+ boolean supportsCallOnHold,
+ @ButtonState int swapToSecondaryButtonState) {
this.state = state;
this.isVideoCall = isVideoCall;
this.sessionModificationState = sessionModificationState;
@@ -115,6 +134,7 @@
this.isRemotelyHeld = isRemotelyHeld;
this.isBusinessNumber = isBusinessNumber;
this.supportsCallOnHold = supportsCallOnHold;
+ this.swapToSecondaryButtonState = swapToSecondaryButtonState;
}
@Override
diff --git a/java/com/android/incallui/res/drawable/spam_notification_icon.xml b/java/com/android/incallui/res/drawable/spam_notification_icon.xml
index a26e7d4..a414428 100644
--- a/java/com/android/incallui/res/drawable/spam_notification_icon.xml
+++ b/java/com/android/incallui/res/drawable/spam_notification_icon.xml
@@ -22,8 +22,8 @@
<shape android:shape="oval">
<solid android:color="@color/incall_call_spam_background_color"/>
<size
- android:height="@dimen/notification_large_icon_height"
- android:width="@dimen/notification_large_icon_width"/>
+ android:height="@android:dimen/notification_large_icon_height"
+ android:width="@android:dimen/notification_large_icon_width"/>
</shape>
</item>
@@ -31,4 +31,4 @@
android:drawable="@drawable/quantum_ic_report_white_36"
android:gravity="center"/>
-</layer-list>
\ No newline at end of file
+</layer-list>
diff --git a/java/com/android/incallui/res/drawable/unknown_notification_icon.xml b/java/com/android/incallui/res/drawable/unknown_notification_icon.xml
deleted file mode 100644
index 5ab07ec..0000000
--- a/java/com/android/incallui/res/drawable/unknown_notification_icon.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2016 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item>
- <shape android:shape="oval">
- <solid android:color="@color/unknown_number_color"/>
- <size
- android:height="@dimen/notification_large_icon_height"
- android:width="@dimen/notification_large_icon_width"/>
- </shape>
- </item>
-
- <item
- android:drawable="@drawable/ic_question_mark"
- android:gravity="center"/>
-
-</layer-list>
\ No newline at end of file
diff --git a/java/com/android/incallui/spam/SpamCallListListener.java b/java/com/android/incallui/spam/SpamCallListListener.java
index b9c70eb..56ae558 100644
--- a/java/com/android/incallui/spam/SpamCallListListener.java
+++ b/java/com/android/incallui/spam/SpamCallListListener.java
@@ -197,7 +197,6 @@
private void showNonSpamCallNotification(DialerCall call) {
Notification.Builder notificationBuilder =
createAfterCallNotificationBuilder(call)
- .setLargeIcon(Icon.createWithResource(context, R.drawable.unknown_notification_icon))
.setContentText(
context.getString(R.string.spam_notification_non_spam_call_collapsed_text))
.setStyle(
diff --git a/java/com/android/incallui/video/impl/CameraPermissionDialogFragment.java b/java/com/android/incallui/video/impl/CameraPermissionDialogFragment.java
deleted file mode 100644
index 9e5ab3c..0000000
--- a/java/com/android/incallui/video/impl/CameraPermissionDialogFragment.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.incallui.video.impl;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
-import com.android.dialer.common.FragmentUtils;
-
-/** Dialog fragment to ask for camera permission from user. */
-public class CameraPermissionDialogFragment extends DialogFragment {
-
- static CameraPermissionDialogFragment newInstance() {
- CameraPermissionDialogFragment fragment = new CameraPermissionDialogFragment();
- return fragment;
- }
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle bundle) {
- return new AlertDialog.Builder(getContext())
- .setTitle(R.string.camera_permission_dialog_title)
- .setMessage(R.string.camera_permission_dialog_message)
- .setPositiveButton(
- R.string.camera_permission_dialog_positive_button,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- CameraPermissionDialogCallback fragment =
- FragmentUtils.getParentUnsafe(
- CameraPermissionDialogFragment.this, CameraPermissionDialogCallback.class);
- fragment.onCameraPermissionGranted();
- }
- })
- .setNegativeButton(
- R.string.camera_permission_dialog_negative_button,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- })
- .create();
- }
-
- /** Callback for being granted camera permission. */
- public interface CameraPermissionDialogCallback {
- void onCameraPermissionGranted();
- }
-}
diff --git a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
index 489f72b..95bdd6b 100644
--- a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
+++ b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java
@@ -50,6 +50,7 @@
import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.ActivityCompat;
+import com.android.dialer.util.PermissionsUtil;
import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment;
import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter;
import com.android.incallui.contactgrid.ContactGridManager;
@@ -65,7 +66,6 @@
import com.android.incallui.incall.protocol.PrimaryCallState;
import com.android.incallui.incall.protocol.PrimaryInfo;
import com.android.incallui.incall.protocol.SecondaryInfo;
-import com.android.incallui.video.impl.CameraPermissionDialogFragment.CameraPermissionDialogCallback;
import com.android.incallui.video.impl.CheckableImageButton.OnCheckedChangeListener;
import com.android.incallui.video.protocol.VideoCallScreen;
import com.android.incallui.video.protocol.VideoCallScreenDelegate;
@@ -85,15 +85,12 @@
OnClickListener,
OnCheckedChangeListener,
AudioRouteSelectorPresenter,
- OnSystemUiVisibilityChangeListener,
- CameraPermissionDialogCallback {
+ OnSystemUiVisibilityChangeListener {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
static final String ARG_CALL_ID = "call_id";
private static final int CAMERA_PERMISSION_REQUEST_CODE = 1;
- private static final String CAMERA_PERMISSION_DIALOG_FRAMENT_TAG =
- "CameraPermissionDialogFragment";
private static final long CAMERA_PERMISSION_DIALOG_DELAY_IN_MILLIS = 2000L;
private static final long VIDEO_OFF_VIEW_FADE_OUT_DELAY_IN_MILLIS = 2000L;
@@ -131,7 +128,7 @@
new Runnable() {
@Override
public void run() {
- if (videoCallScreenDelegate.shouldShowCameraPermissionDialog()) {
+ if (videoCallScreenDelegate.shouldShowCameraPermissionToast()) {
LogUtil.i(
"SurfaceViewVideoCallFragment.cameraPermissionDialogRunnable", "showing dialog");
checkCameraPermission();
@@ -612,7 +609,7 @@
@Override
public void onCheckedChanged(CheckableImageButton button, boolean isChecked) {
if (button == cameraOffButton) {
- if (!isChecked && !VideoUtils.hasCameraPermissionAndAllowedByUser(getContext())) {
+ if (!isChecked && !VideoUtils.hasCameraPermissionAndShownPrivacyToast(getContext())) {
LogUtil.i("SurfaceViewVideoCallFragment.onCheckedChanged", "show camera permission dialog");
checkCameraPermission();
} else {
@@ -1048,24 +1045,19 @@
}
}
- @Override
- public void onCameraPermissionGranted() {
- videoCallScreenDelegate.onCameraPermissionGranted();
- }
-
private void checkCameraPermission() {
// Checks if user has consent of camera permission and the permission is granted.
// If camera permission is revoked, shows system permission dialog.
// If camera permission is granted but user doesn't have consent of camera permission
// (which means it's first time making video call), shows custom dialog instead. This
// will only be shown to user once.
- if (!VideoUtils.hasCameraPermissionAndAllowedByUser(getContext())) {
+ if (!VideoUtils.hasCameraPermissionAndShownPrivacyToast(getContext())) {
videoCallScreenDelegate.onCameraPermissionDialogShown();
if (!VideoUtils.hasCameraPermission(getContext())) {
requestPermissions(new String[] {permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
} else {
- CameraPermissionDialogFragment.newInstance()
- .show(getChildFragmentManager(), CAMERA_PERMISSION_DIALOG_FRAMENT_TAG);
+ PermissionsUtil.showCameraPermissionToast(getContext());
+ videoCallScreenDelegate.onCameraPermissionGranted();
}
}
}
diff --git a/java/com/android/incallui/video/impl/VideoCallFragment.java b/java/com/android/incallui/video/impl/VideoCallFragment.java
index 4d17223..84e01bd 100644
--- a/java/com/android/incallui/video/impl/VideoCallFragment.java
+++ b/java/com/android/incallui/video/impl/VideoCallFragment.java
@@ -61,6 +61,7 @@
import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.ActivityCompat;
+import com.android.dialer.util.PermissionsUtil;
import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment;
import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter;
import com.android.incallui.contactgrid.ContactGridManager;
@@ -76,7 +77,6 @@
import com.android.incallui.incall.protocol.PrimaryCallState;
import com.android.incallui.incall.protocol.PrimaryInfo;
import com.android.incallui.incall.protocol.SecondaryInfo;
-import com.android.incallui.video.impl.CameraPermissionDialogFragment.CameraPermissionDialogCallback;
import com.android.incallui.video.impl.CheckableImageButton.OnCheckedChangeListener;
import com.android.incallui.video.protocol.VideoCallScreen;
import com.android.incallui.video.protocol.VideoCallScreenDelegate;
@@ -94,8 +94,7 @@
OnClickListener,
OnCheckedChangeListener,
AudioRouteSelectorPresenter,
- OnSystemUiVisibilityChangeListener,
- CameraPermissionDialogCallback {
+ OnSystemUiVisibilityChangeListener {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
static final String ARG_CALL_ID = "call_id";
@@ -107,8 +106,6 @@
private static final float ASPECT_RATIO_MATCH_THRESHOLD = 0.2f;
private static final int CAMERA_PERMISSION_REQUEST_CODE = 1;
- private static final String CAMERA_PERMISSION_DIALOG_FRAMENT_TAG =
- "CameraPermissionDialogFragment";
private static final long CAMERA_PERMISSION_DIALOG_DELAY_IN_MILLIS = 2000L;
private static final long VIDEO_OFF_VIEW_FADE_OUT_DELAY_IN_MILLIS = 2000L;
@@ -158,7 +155,7 @@
new Runnable() {
@Override
public void run() {
- if (videoCallScreenDelegate.shouldShowCameraPermissionDialog()) {
+ if (videoCallScreenDelegate.shouldShowCameraPermissionToast()) {
LogUtil.i("VideoCallFragment.cameraPermissionDialogRunnable", "showing dialog");
checkCameraPermission();
}
@@ -653,7 +650,7 @@
@Override
public void onCheckedChanged(CheckableImageButton button, boolean isChecked) {
if (button == cameraOffButton) {
- if (!isChecked && !VideoUtils.hasCameraPermissionAndAllowedByUser(getContext())) {
+ if (!isChecked && !VideoUtils.hasCameraPermissionAndShownPrivacyToast(getContext())) {
LogUtil.i("VideoCallFragment.onCheckedChanged", "show camera permission dialog");
checkCameraPermission();
} else {
@@ -1256,24 +1253,19 @@
videoCallScreenDelegate.onSystemUiVisibilityChange(navBarVisible);
}
- @Override
- public void onCameraPermissionGranted() {
- videoCallScreenDelegate.onCameraPermissionGranted();
- }
-
private void checkCameraPermission() {
// Checks if user has consent of camera permission and the permission is granted.
// If camera permission is revoked, shows system permission dialog.
// If camera permission is granted but user doesn't have consent of camera permission
// (which means it's first time making video call), shows custom dialog instead. This
// will only be shown to user once.
- if (!VideoUtils.hasCameraPermissionAndAllowedByUser(getContext())) {
+ if (!VideoUtils.hasCameraPermissionAndShownPrivacyToast(getContext())) {
videoCallScreenDelegate.onCameraPermissionDialogShown();
if (!VideoUtils.hasCameraPermission(getContext())) {
requestPermissions(new String[] {permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
} else {
- CameraPermissionDialogFragment.newInstance()
- .show(getChildFragmentManager(), CAMERA_PERMISSION_DIALOG_FRAMENT_TAG);
+ PermissionsUtil.showCameraPermissionToast(getContext());
+ videoCallScreenDelegate.onCameraPermissionGranted();
}
}
}
diff --git a/java/com/android/incallui/video/protocol/VideoCallScreenDelegate.java b/java/com/android/incallui/video/protocol/VideoCallScreenDelegate.java
index e7e69df..55ea23f 100644
--- a/java/com/android/incallui/video/protocol/VideoCallScreenDelegate.java
+++ b/java/com/android/incallui/video/protocol/VideoCallScreenDelegate.java
@@ -37,7 +37,7 @@
void onCameraPermissionGranted();
- boolean shouldShowCameraPermissionDialog();
+ boolean shouldShowCameraPermissionToast();
void onCameraPermissionDialogShown();
diff --git a/java/com/android/incallui/videotech/ims/ImsVideoTech.java b/java/com/android/incallui/videotech/ims/ImsVideoTech.java
index 8fa983a..641d436 100644
--- a/java/com/android/incallui/videotech/ims/ImsVideoTech.java
+++ b/java/com/android/incallui/videotech/ims/ImsVideoTech.java
@@ -42,6 +42,7 @@
SessionModificationState.NO_REQUEST;
private int previousVideoState = VideoProfile.STATE_AUDIO_ONLY;
private boolean paused = false;
+ private String savedCameraId;
// Hold onto a flag of whether or not stopTransmission was called but resumeTransmission has not
// been. This is needed because there is time between calling stopTransmission and
@@ -236,9 +237,25 @@
@Override
public void pause() {
- if (canPause() && !paused) {
+ if (call.getState() != Call.STATE_ACTIVE) {
+ LogUtil.i("ImsVideoTech.pause", "not pausing because call is not active");
+ return;
+ }
+
+ if (!isTransmittingOrReceiving()) {
+ LogUtil.i("ImsVideoTech.pause", "not pausing because this is not a video call");
+ return;
+ }
+
+ if (paused) {
+ LogUtil.i("ImsVideoTech.pause", "already paused");
+ return;
+ }
+
+ paused = true;
+
+ if (canPause()) {
LogUtil.i("ImsVideoTech.pause", "sending pause request");
- paused = true;
int pausedVideoState = call.getDetails().getVideoState() | VideoProfile.STATE_PAUSED;
if (transmissionStopped && VideoProfile.isTransmissionEnabled(pausedVideoState)) {
LogUtil.i("ImsVideoTech.pause", "overriding TX to false due to user request");
@@ -246,19 +263,33 @@
}
call.getVideoCall().sendSessionModifyRequest(new VideoProfile(pausedVideoState));
} else {
- LogUtil.i(
- "ImsVideoTech.pause",
- "not sending request: canPause: %b, paused: %b",
- canPause(),
- paused);
+ // This video call does not support pause so we fall back to disabling the camera
+ LogUtil.i("ImsVideoTech.pause", "disabling camera");
+ call.getVideoCall().setCamera(null);
}
}
@Override
public void unpause() {
- if (canPause() && paused) {
+ if (call.getState() != Call.STATE_ACTIVE) {
+ LogUtil.i("ImsVideoTech.unpause", "not unpausing because call is not active");
+ return;
+ }
+
+ if (!isTransmittingOrReceiving()) {
+ LogUtil.i("ImsVideoTech.unpause", "not unpausing because this is not a video call");
+ return;
+ }
+
+ if (!paused) {
+ LogUtil.i("ImsVideoTech.unpause", "already unpaused");
+ return;
+ }
+
+ paused = false;
+
+ if (canPause()) {
LogUtil.i("ImsVideoTech.unpause", "sending unpause request");
- paused = false;
int unpausedVideoState = getUnpausedVideoState(call.getDetails().getVideoState());
if (transmissionStopped && VideoProfile.isTransmissionEnabled(unpausedVideoState)) {
LogUtil.i("ImsVideoTech.unpause", "overriding TX to false due to user request");
@@ -266,16 +297,15 @@
}
call.getVideoCall().sendSessionModifyRequest(new VideoProfile(unpausedVideoState));
} else {
- LogUtil.i(
- "ImsVideoTech.unpause",
- "not sending request: canPause: %b, paused: %b",
- canPause(),
- paused);
+ // This video call does not support pause so we fall back to re-enabling the camera
+ LogUtil.i("ImsVideoTech.pause", "re-enabling camera");
+ setCamera(savedCameraId);
}
}
@Override
public void setCamera(@Nullable String cameraId) {
+ savedCameraId = cameraId;
call.getVideoCall().setCamera(cameraId);
call.getVideoCall().requestCameraCapabilities();
}
@@ -286,9 +316,7 @@
}
private boolean canPause() {
- return call.getDetails().can(Details.CAPABILITY_CAN_PAUSE_VIDEO)
- && call.getState() == Call.STATE_ACTIVE
- && isTransmittingOrReceiving();
+ return call.getDetails().can(Details.CAPABILITY_CAN_PAUSE_VIDEO);
}
static int getUnpausedVideoState(int videoState) {
diff --git a/java/com/android/incallui/videotech/lightbringer/LightbringerTech.java b/java/com/android/incallui/videotech/lightbringer/LightbringerTech.java
index 55ee2db..961de9e 100644
--- a/java/com/android/incallui/videotech/lightbringer/LightbringerTech.java
+++ b/java/com/android/incallui/videotech/lightbringer/LightbringerTech.java
@@ -91,7 +91,9 @@
}
@Override
- public void onRemovedFromCallList() {}
+ public void onRemovedFromCallList() {
+ lightbringer.unregisterListener(this);
+ }
@Override
public int getSessionModificationState() {
diff --git a/java/com/android/incallui/videotech/utils/VideoUtils.java b/java/com/android/incallui/videotech/utils/VideoUtils.java
index 5276540..9dfc687 100644
--- a/java/com/android/incallui/videotech/utils/VideoUtils.java
+++ b/java/com/android/incallui/videotech/utils/VideoUtils.java
@@ -20,12 +20,10 @@
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
-import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.PermissionsUtil;
public class VideoUtils {
- private static final String PREFERENCE_CAMERA_ALLOWED_BY_USER = "camera_allowed_by_user";
-
public static boolean hasSentVideoUpgradeRequest(@SessionModificationState int state) {
return state == SessionModificationState.WAITING_FOR_UPGRADE_TO_VIDEO_RESPONSE
|| state == SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_FAILED
@@ -37,24 +35,12 @@
return state == SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
}
- public static boolean hasCameraPermissionAndAllowedByUser(@NonNull Context context) {
- return isCameraAllowedByUser(context) && hasCameraPermission(context);
+ public static boolean hasCameraPermissionAndShownPrivacyToast(@NonNull Context context) {
+ return PermissionsUtil.hasCameraPrivacyToastShown(context) && hasCameraPermission(context);
}
public static boolean hasCameraPermission(@NonNull Context context) {
return ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}
-
- public static boolean isCameraAllowedByUser(@NonNull Context context) {
- return DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context)
- .getBoolean(PREFERENCE_CAMERA_ALLOWED_BY_USER, false);
- }
-
- public static void setCameraAllowedByUser(@NonNull Context context) {
- DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context)
- .edit()
- .putBoolean(PREFERENCE_CAMERA_ALLOWED_BY_USER, true)
- .apply();
- }
}
diff --git a/java/com/android/voicemail/AndroidManifest.xml b/java/com/android/voicemail/AndroidManifest.xml
index aedfd6f..817cf1b 100644
--- a/java/com/android/voicemail/AndroidManifest.xml
+++ b/java/com/android/voicemail/AndroidManifest.xml
@@ -14,7 +14,7 @@
~ limitations under the License
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.voicemailomtp">
+ package="com.android.voicemail">
<uses-sdk
android:minSdkVersion="23"
@@ -32,5 +32,22 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
- <application/>
+ <application>
+ <receiver
+ android:name=".VoicemailSecretCodeReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SECRET_CODE" />
+ <data android:scheme="android_secret_code" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.voicemail.VoicemailPowerCycleReceiver"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="android.intent.action.ACTION_SHUTDOWN" />
+ </intent-filter>
+ </receiver>
+ </application>
</manifest>
diff --git a/java/com/android/voicemail/VoicemailClient.java b/java/com/android/voicemail/VoicemailClient.java
index 97b824b..28d2bf0 100644
--- a/java/com/android/voicemail/VoicemailClient.java
+++ b/java/com/android/voicemail/VoicemailClient.java
@@ -18,7 +18,10 @@
import android.content.Context;
import android.content.Intent;
+import android.os.PersistableBundle;
import android.provider.VoicemailContract.Voicemails;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
@@ -52,6 +55,12 @@
"com.android.voicemail.VoicemailClient.ACTION_SHOW_LEGACY_VOICEMAIL";
/**
+ * Secret code to launch the voicemail config activity intended for OEMs and Carriers. {@code
+ * *#*#VVMCONFIG#*#*}
+ */
+ String VOICEMAIL_SECRET_CODE = "886266344";
+
+ /**
* Whether the visual voicemail service is enabled for the {@code phoneAccountHandle}. "Enable"
* means the user "wants" to have this service on, and does not mean the service is actually
* functional(For example, the service is blocked on the carrier side. The service will be
@@ -122,4 +131,21 @@
* provisioning. Being "activated" means all setup are completed, and VVM is expected to work.
*/
boolean isActivated(Context context, PhoneAccountHandle phoneAccountHandle);
+
+ /**
+ * Called when {@link #VOICEMAIL_SECRET_CODE} is dialed. {@code context} will be a broadcast
+ * receiver context.
+ */
+ @MainThread
+ void showConfigUi(@NonNull Context context);
+
+ @NonNull
+ PersistableBundle getConfig(
+ @NonNull Context context, @Nullable PhoneAccountHandle phoneAccountHandle);
+
+ @MainThread
+ void onBoot(@NonNull Context context);
+
+ @MainThread
+ void onShutdown(@NonNull Context context);
}
diff --git a/java/com/android/voicemail/VoicemailPowerCycleReceiver.java b/java/com/android/voicemail/VoicemailPowerCycleReceiver.java
new file mode 100644
index 0000000..e9362b4
--- /dev/null
+++ b/java/com/android/voicemail/VoicemailPowerCycleReceiver.java
@@ -0,0 +1,38 @@
+/*
+ * 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.voicemail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import com.android.dialer.common.Assert;
+
+/** Receives {@link Intent#ACTION_BOOT_COMPLETED} and {@link Intent#ACTION_SHUTDOWN} */
+public class VoicemailPowerCycleReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ VoicemailClient voicemailClient = VoicemailComponent.get(context).getVoicemailClient();
+ if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+ voicemailClient.onBoot(context);
+ } else if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
+ voicemailClient.onShutdown(context);
+ } else {
+ throw Assert.createAssertionFailException("unexpected action: " + intent.getAction());
+ }
+ }
+}
diff --git a/java/com/android/voicemail/VoicemailSecretCodeReceiver.java b/java/com/android/voicemail/VoicemailSecretCodeReceiver.java
new file mode 100644
index 0000000..6d14241
--- /dev/null
+++ b/java/com/android/voicemail/VoicemailSecretCodeReceiver.java
@@ -0,0 +1,36 @@
+/*
+ * 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.voicemail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import com.android.dialer.common.LogUtil;
+
+/** Receives android.provider.Telephony.SECRET_CODE */
+public class VoicemailSecretCodeReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String host = intent.getData().getHost();
+ if (!VoicemailClient.VOICEMAIL_SECRET_CODE.equals(host)) {
+ return;
+ }
+ LogUtil.i("VoicemailSecretCodeReceiver.onReceive", "secret code received");
+ VoicemailComponent.get(context).getVoicemailClient().showConfigUi(context);
+ }
+}
diff --git a/java/com/android/voicemail/impl/ActivationTask.java b/java/com/android/voicemail/impl/ActivationTask.java
index 6e27b50..320ea2a 100644
--- a/java/com/android/voicemail/impl/ActivationTask.java
+++ b/java/com/android/voicemail/impl/ActivationTask.java
@@ -36,7 +36,6 @@
import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
import com.android.voicemail.impl.sms.StatusMessage;
import com.android.voicemail.impl.sms.StatusSmsFetcher;
-import com.android.voicemail.impl.sync.OmtpVvmSyncService;
import com.android.voicemail.impl.sync.SyncTask;
import com.android.voicemail.impl.sync.VvmAccountManager;
import com.android.voicemail.impl.utils.LoggerUtils;
@@ -258,7 +257,7 @@
VoicemailStatus.edit(context, phoneAccountHandle),
OmtpEvents.CONFIG_REQUEST_STATUS_SUCCESS);
clearLegacyVoicemailNotification(context, phoneAccountHandle);
- SyncTask.start(context, phoneAccountHandle, OmtpVvmSyncService.SYNC_FULL_SYNC);
+ SyncTask.start(context, phoneAccountHandle);
}
/** Sends a broadcast to the dialer UI to clear legacy voicemail notifications if any. */
diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml
index 6a7e689..fd591be 100644
--- a/java/com/android/voicemail/impl/AndroidManifest.xml
+++ b/java/com/android/voicemail/impl/AndroidManifest.xml
@@ -15,10 +15,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.voicemailomtp">
+ package="com.android.voicemail.impl">
<application
- android:supportsRtl="true">
+ android:allowBackup="false"
+ android:supportsRtl="true"
+ android:usesCleartextTraffic="true"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
<!-- Causes the "Voicemail" item under "Calls" setting to be hidden. The voicemail module will
be handling the settings. Has no effect before OC where dialer cannot provide voicemail
@@ -113,13 +117,6 @@
android:windowSoftInputMode="stateVisible|adjustResize">
</activity>
- <receiver android:name="com.android.voicemail.impl.VoicemailBootReceiver"
- android:exported="false">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED" />
- </intent-filter>
- </receiver>
-
<receiver android:name="com.android.voicemail.impl.PackageReplacedReceiver"
android:exported="false">
<intent-filter>
diff --git a/java/com/android/voicemail/impl/OmtpService.java b/java/com/android/voicemail/impl/OmtpService.java
index b82cc5f..4db1aeb 100644
--- a/java/com/android/voicemail/impl/OmtpService.java
+++ b/java/com/android/voicemail/impl/OmtpService.java
@@ -17,9 +17,13 @@
package com.android.voicemail.impl;
import android.annotation.TargetApi;
+import android.content.Context;
import android.content.Intent;
import android.os.Build.VERSION_CODES;
import android.os.UserManager;
+import android.preference.PreferenceManager;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
import android.telecom.PhoneAccountHandle;
import android.telephony.VisualVoicemailService;
import android.telephony.VisualVoicemailSms;
@@ -40,6 +44,8 @@
public static final String EXTRA_VOICEMAIL_SMS = "extra_voicemail_sms";
+ private static final String IS_SHUTTING_DOWN = "com.android.voicemail.impl.is_shutting_down";
+
@Override
public void onCellServiceConnected(
VisualVoicemailTask task, final PhoneAccountHandle phoneAccountHandle) {
@@ -50,7 +56,7 @@
return;
}
- if (!isUserUnlocked()) {
+ if (!isUserUnlocked(this)) {
VvmLog.i(TAG, "onCellServiceConnected: user locked");
task.finish();
return;
@@ -75,7 +81,7 @@
return;
}
- if (!isUserUnlocked()) {
+ if (!isUserUnlocked(this)) {
LegacyModeSmsHandler.handle(this, sms);
return;
}
@@ -105,12 +111,18 @@
return;
}
- if (!isUserUnlocked()) {
+ if (!isUserUnlocked(this)) {
VvmLog.i(TAG, "onSimRemoved: user locked");
task.finish();
return;
}
+ if (isShuttingDown(this)) {
+ VvmLog.i(TAG, "onSimRemoved: system shutting down, ignoring");
+ task.finish();
+ return;
+ }
+
Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED);
VvmAccountManager.removeAccount(this, phoneAccountHandle);
task.finish();
@@ -124,7 +136,7 @@
task.finish();
return;
}
- if (!isUserUnlocked()) {
+ if (!isUserUnlocked(this)) {
VvmLog.i(TAG, "onStopped: user locked");
task.finish();
return;
@@ -132,6 +144,22 @@
Logger.get(this).logImpression(DialerImpression.Type.VVM_UNBUNDLED_EVENT_RECEIVED);
}
+ @MainThread
+ static void onBoot(@NonNull Context context) {
+ VvmLog.i(TAG, "onBoot");
+ Assert.isTrue(isUserUnlocked(context));
+ Assert.isMainThread();
+ setShuttingDown(context, false);
+ }
+
+ @MainThread
+ static void onShutdown(@NonNull Context context) {
+ VvmLog.i(TAG, "onShutdown");
+ Assert.isTrue(isUserUnlocked(context));
+ Assert.isMainThread();
+ setShuttingDown(context, true);
+ }
+
private boolean isModuleEnabled() {
return VoicemailComponent.get(this).getVoicemailClient().isVoicemailModuleEnabled();
}
@@ -150,8 +178,20 @@
return true;
}
- private boolean isUserUnlocked() {
- UserManager userManager = getSystemService(UserManager.class);
+ private static boolean isUserUnlocked(@NonNull Context context) {
+ UserManager userManager = context.getSystemService(UserManager.class);
return userManager.isUserUnlocked();
}
+
+ private static void setShuttingDown(Context context, boolean value) {
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putBoolean(IS_SHUTTING_DOWN, value)
+ .apply();
+ }
+
+ private static boolean isShuttingDown(Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean(IS_SHUTTING_DOWN, false);
+ }
}
diff --git a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
index 4a9e433..700e1cb 100644
--- a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
+++ b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
@@ -15,9 +15,11 @@
*/
package com.android.voicemail.impl;
+import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.annotation.NonNull;
@@ -30,6 +32,7 @@
import android.text.TextUtils;
import android.util.ArraySet;
import com.android.dialer.common.Assert;
+import com.android.voicemail.impl.configui.ConfigOverrideFragment;
import com.android.voicemail.impl.protocol.VisualVoicemailProtocol;
import com.android.voicemail.impl.protocol.VisualVoicemailProtocolFactory;
import com.android.voicemail.impl.sms.StatusMessage;
@@ -48,27 +51,28 @@
*
* <p>The current hidden configs are: {@link #getSslPort()} {@link #getDisabledCapabilities()}
*/
+@TargetApi(VERSION_CODES.O)
public class OmtpVvmCarrierConfigHelper {
private static final String TAG = "OmtpVvmCarrierCfgHlpr";
- static final String KEY_VVM_TYPE_STRING = CarrierConfigManager.KEY_VVM_TYPE_STRING;
- static final String KEY_VVM_DESTINATION_NUMBER_STRING =
+ public static final String KEY_VVM_TYPE_STRING = CarrierConfigManager.KEY_VVM_TYPE_STRING;
+ public static final String KEY_VVM_DESTINATION_NUMBER_STRING =
CarrierConfigManager.KEY_VVM_DESTINATION_NUMBER_STRING;
- static final String KEY_VVM_PORT_NUMBER_INT = CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT;
- static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING =
+ public static final String KEY_VVM_PORT_NUMBER_INT = CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT;
+ public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING =
CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING;
- static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY =
+ public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY =
"carrier_vvm_package_name_string_array";
- static final String KEY_VVM_PREFETCH_BOOL = CarrierConfigManager.KEY_VVM_PREFETCH_BOOL;
- static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL =
+ public static final String KEY_VVM_PREFETCH_BOOL = CarrierConfigManager.KEY_VVM_PREFETCH_BOOL;
+ public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL =
CarrierConfigManager.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL;
/** @see #getSslPort() */
- static final String KEY_VVM_SSL_PORT_NUMBER_INT = "vvm_ssl_port_number_int";
+ public static final String KEY_VVM_SSL_PORT_NUMBER_INT = "vvm_ssl_port_number_int";
/** @see #isLegacyModeEnabled() */
- static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
+ public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
/**
* Ban a capability reported by the server from being used. The array of string should be a subset
@@ -76,10 +80,10 @@
*
* @see #getDisabledCapabilities()
*/
- static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
+ public static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
"vvm_disabled_capabilities_string_array";
- static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
+ public static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
private final Context mContext;
private final PersistableBundle mCarrierConfig;
@@ -87,6 +91,8 @@
private final VisualVoicemailProtocol mProtocol;
private final PersistableBundle mTelephonyConfig;
+ @Nullable private final PersistableBundle mOverrideConfig;
+
private PhoneAccountHandle mPhoneAccountHandle;
public OmtpVvmCarrierConfigHelper(Context context, @Nullable PhoneAccountHandle handle) {
@@ -100,6 +106,7 @@
VvmLog.e(TAG, "PhoneAccountHandle is invalid");
mCarrierConfig = null;
mTelephonyConfig = null;
+ mOverrideConfig = null;
mVvmType = null;
mProtocol = null;
return;
@@ -111,6 +118,13 @@
mVvmType = getVvmType();
mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
+
+ if (ConfigOverrideFragment.isOverridden(context)) {
+ mOverrideConfig = ConfigOverrideFragment.getConfig(context);
+ VvmLog.w(TAG, "Config override is activated: " + mOverrideConfig);
+ } else {
+ mOverrideConfig = null;
+ }
}
@VisibleForTesting
@@ -119,10 +133,23 @@
mContext = context;
mCarrierConfig = carrierConfig;
mTelephonyConfig = telephonyConfig;
+ mOverrideConfig = null;
mVvmType = getVvmType();
mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
}
+ public PersistableBundle getConfig() {
+ PersistableBundle result = new PersistableBundle();
+ if (mTelephonyConfig != null) {
+ result.putAll(mTelephonyConfig);
+ }
+ if (mCarrierConfig != null) {
+ result.putAll(mCarrierConfig);
+ }
+
+ return result;
+ }
+
public Context getContext() {
return mContext;
}
@@ -426,6 +453,13 @@
@Nullable
private Object getValue(String key, Object defaultValue) {
Object result;
+ if (mOverrideConfig != null) {
+ result = mOverrideConfig.get(key);
+ if (result != null) {
+ return result;
+ }
+ }
+
if (mCarrierConfig != null) {
result = mCarrierConfig.get(key);
if (result != null) {
diff --git a/java/com/android/voicemail/impl/VoicemailBootReceiver.java b/java/com/android/voicemail/impl/VoicemailBootReceiver.java
deleted file mode 100644
index 0a3e61a..0000000
--- a/java/com/android/voicemail/impl/VoicemailBootReceiver.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Copyright (C) 2017 The Android Open Source Project
- *
- * <p>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
- *
- * <p>http://www.apache.org/licenses/LICENSE-2.0
- *
- * <p>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.voicemail.impl;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import com.android.voicemail.VoicemailComponent;
-
-/** Receives {@link Intent#ACTION_BOOT_COMPLETED} for the voicemail module. */
-public class VoicemailBootReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!VoicemailComponent.get(context).getVoicemailClient().isVoicemailModuleEnabled()) {
- return;
- }
- StatusCheckJobService.schedule(context);
- }
-}
diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java
index 83ce6c5..1b98903 100644
--- a/java/com/android/voicemail/impl/VoicemailClientImpl.java
+++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java
@@ -17,8 +17,11 @@
import android.content.Context;
import android.content.Intent;
import android.os.Build.VERSION_CODES;
+import android.os.PersistableBundle;
import android.provider.VoicemailContract.Status;
import android.provider.VoicemailContract.Voicemails;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.BuildCompat;
import android.telecom.PhoneAccountHandle;
@@ -28,6 +31,7 @@
import com.android.dialer.configprovider.ConfigProviderBindings;
import com.android.voicemail.VisualVoicemailTypeExtensions;
import com.android.voicemail.VoicemailClient;
+import com.android.voicemail.impl.configui.VoicemailSecretCodeActivity;
import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
import com.android.voicemail.impl.settings.VoicemailChangePinActivity;
import com.android.voicemail.impl.settings.VoicemailSettingsFragment;
@@ -126,6 +130,31 @@
return VvmAccountManager.isAccountActivated(context, phoneAccountHandle);
}
+ @Override
+ public void showConfigUi(@NonNull Context context) {
+ Intent intent = new Intent(context, VoicemailSecretCodeActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+ }
+
+ @Override
+ public PersistableBundle getConfig(Context context, PhoneAccountHandle phoneAccountHandle) {
+ return new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle).getConfig();
+ }
+
+ @Override
+ @MainThread
+ public void onBoot(@NonNull Context context) {
+ OmtpService.onBoot(context);
+ StatusCheckJobService.schedule(context);
+ }
+
+ @Override
+ @MainThread
+ public void onShutdown(@NonNull Context context) {
+ OmtpService.onShutdown(context);
+ }
+
@TargetApi(VERSION_CODES.O)
@Override
public void appendOmtpVoicemailSelectionClause(
diff --git a/java/com/android/voicemail/impl/VvmPhoneStateListener.java b/java/com/android/voicemail/impl/VvmPhoneStateListener.java
index 13d399d..00c1358 100644
--- a/java/com/android/voicemail/impl/VvmPhoneStateListener.java
+++ b/java/com/android/voicemail/impl/VvmPhoneStateListener.java
@@ -19,7 +19,6 @@
import android.telecom.PhoneAccountHandle;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
-import com.android.voicemail.impl.sync.OmtpVvmSyncService;
import com.android.voicemail.impl.sync.SyncTask;
import com.android.voicemail.impl.sync.VoicemailStatusQueryHelper;
import com.android.voicemail.impl.sync.VvmAccountManager;
@@ -82,7 +81,7 @@
VvmLog.v(TAG, "Signal returned: requesting resync for " + mPhoneAccount);
// If the source is already registered, run a full sync in case something was missed
// while signal was down.
- SyncTask.start(mContext, mPhoneAccount, OmtpVvmSyncService.SYNC_FULL_SYNC);
+ SyncTask.start(mContext, mPhoneAccount);
} else {
VvmLog.v(TAG, "Signal returned: reattempting activation for " + mPhoneAccount);
// Otherwise initiate an activation because this means that an OMTP source was
diff --git a/java/com/android/voicemail/impl/configui/AndroidManifest.xml b/java/com/android/voicemail/impl/configui/AndroidManifest.xml
new file mode 100644
index 0000000..95796f9
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.voicemail.impl.configui">
+
+ <application>
+ <activity android:name="com.android.voicemail.impl.configui.VoicemailSecretCodeActivity"
+ android:exported="false">
+ </activity>
+ </application>
+</manifest>
diff --git a/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java b/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java
new file mode 100644
index 0000000..18b2b92
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java
@@ -0,0 +1,175 @@
+/*
+ * 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.voicemail.impl.configui;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.text.TextUtils;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.concurrent.ThreadUtil;
+import com.android.voicemail.VoicemailComponent;
+
+/**
+ * Fragment to edit the override values for the {@link import
+ * com.android.voicemail.impl.OmtpVvmCarrierConfigHelper}
+ */
+public class ConfigOverrideFragment extends PreferenceFragment
+ implements OnPreferenceChangeListener {
+
+ /**
+ * Any preference with key that starts with this prefix will be written to the dialer carrier
+ * config.
+ */
+ @VisibleForTesting static final String CONFIG_OVERRIDE_KEY_PREFIX = "vvm_config_override_key_";
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ PreferenceManager.setDefaultValues(getActivity(), R.xml.vvm_config_override, false);
+ addPreferencesFromResource(R.xml.vvm_config_override);
+
+ // add listener so the value of a EditTextPreference will be updated to the summary.
+ for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
+ Preference preference = getPreferenceScreen().getPreference(i);
+ preference.setOnPreferenceChangeListener(this);
+ updatePreference(preference);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Assert.isMainThread();
+ ThreadUtil.postOnUiThread(() -> updatePreference(preference));
+ return true;
+ }
+
+ private void updatePreference(Preference preference) {
+ if (preference instanceof EditTextPreference) {
+ EditTextPreference editTextPreference = (EditTextPreference) preference;
+ editTextPreference.setSummary(editTextPreference.getText());
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (TextUtils.equals(
+ preference.getKey(), getString(R.string.vvm_config_override_load_current_key))) {
+ loadCurrentConfig();
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ /**
+ * Loads the config for the currently carrier into the override values, from the dialer or the
+ * carrier config app. This is a "reset" button to load the defaults.
+ */
+ private void loadCurrentConfig() {
+ Context context = getActivity();
+ PhoneAccountHandle phoneAccountHandle =
+ context
+ .getSystemService(TelecomManager.class)
+ .getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_VOICEMAIL);
+
+ PersistableBundle config =
+ VoicemailComponent.get(context).getVoicemailClient().getConfig(context, phoneAccountHandle);
+
+ for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
+ Preference preference = getPreferenceScreen().getPreference(i);
+ String key = preference.getKey();
+ if (!key.startsWith(CONFIG_OVERRIDE_KEY_PREFIX)) {
+ continue;
+ }
+
+ String configKey = key.substring(CONFIG_OVERRIDE_KEY_PREFIX.length());
+
+ if (configKey.endsWith("bool")) {
+ ((SwitchPreference) preference).setChecked(config.getBoolean(configKey));
+ } else if (configKey.endsWith("int")) {
+ ((EditTextPreference) preference).setText(String.valueOf(config.getInt(configKey)));
+ } else if (configKey.endsWith("string")) {
+ ((EditTextPreference) preference).setText(config.getString(configKey));
+ } else if (configKey.endsWith("string_array")) {
+ ((EditTextPreference) preference).setText(toCsv(config.getStringArray(configKey)));
+ } else {
+ throw Assert.createAssertionFailException("unknown type for key " + configKey);
+ }
+ updatePreference(preference);
+ }
+ }
+
+ public static boolean isOverridden(Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getBoolean(context.getString(R.string.vvm_config_override_enabled_key), false);
+ }
+
+ public static PersistableBundle getConfig(Context context) {
+ Assert.checkState(isOverridden(context));
+ PersistableBundle result = new PersistableBundle();
+
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+ for (String key : preferences.getAll().keySet()) {
+ if (!key.startsWith(CONFIG_OVERRIDE_KEY_PREFIX)) {
+ continue;
+ }
+ String configKey = key.substring(CONFIG_OVERRIDE_KEY_PREFIX.length());
+ if (configKey.endsWith("bool")) {
+ result.putBoolean(configKey, preferences.getBoolean(key, false));
+ } else if (configKey.endsWith("int")) {
+ result.putInt(configKey, Integer.valueOf(preferences.getString(key, null)));
+ } else if (configKey.endsWith("string")) {
+ result.putString(configKey, preferences.getString(key, null));
+ } else if (configKey.endsWith("string_array")) {
+ result.putStringArray(configKey, fromCsv(preferences.getString(key, null)));
+ } else {
+ throw Assert.createAssertionFailException("unknown type for key " + configKey);
+ }
+ }
+ return result;
+ }
+
+ private static String toCsv(String[] array) {
+ if (array == null) {
+ return "";
+ }
+ StringBuilder result = new StringBuilder();
+ for (String element : array) {
+ if (result.length() != 0) {
+ result.append(",");
+ }
+ result.append(element);
+ }
+ return result.toString();
+ };
+
+ private static String[] fromCsv(String csv) {
+ return csv.split(",");
+ }
+}
diff --git a/java/com/android/voicemail/impl/configui/VoicemailSecretCodeActivity.java b/java/com/android/voicemail/impl/configui/VoicemailSecretCodeActivity.java
new file mode 100644
index 0000000..beeb956
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/VoicemailSecretCodeActivity.java
@@ -0,0 +1,58 @@
+/*
+ * 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.voicemail.impl.configui;
+
+import android.content.Intent;
+import android.preference.PreferenceActivity;
+import android.provider.VoicemailContract;
+import java.util.List;
+
+/** Activity launched by simulator->voicemail, provides debug features. */
+@SuppressWarnings("FragmentInjection") // not exported
+public class VoicemailSecretCodeActivity extends PreferenceActivity {
+
+ private Header syncHeader;
+
+ @Override
+ public void onBuildHeaders(List<Header> target) {
+ super.onBuildHeaders(target);
+ syncHeader = new Header();
+ syncHeader.title = "Sync";
+ target.add(syncHeader);
+
+ Header configOverride = new Header();
+ configOverride.fragment = ConfigOverrideFragment.class.getName();
+ configOverride.title = "VVM config override";
+ target.add(configOverride);
+ }
+
+ @Override
+ public void onHeaderClick(Header header, int position) {
+ if (header == syncHeader) {
+ Intent intent = new Intent(VoicemailContract.ACTION_SYNC_VOICEMAIL);
+ intent.setPackage(getPackageName());
+ sendBroadcast(intent);
+ return;
+ }
+ super.onHeaderClick(header, position);
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ return true;
+ }
+}
diff --git a/java/com/android/voicemail/impl/configui/res/values/strings.xml b/java/com/android/voicemail/impl/configui/res/values/strings.xml
new file mode 100644
index 0000000..fea76be
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="vvm_config_override_load_current_key" translatable="false">vvm_config_override_load_current</string>
+ <string name="vvm_config_override_enabled_key" translatable="false">vvm_config_override_enabled</string>
+
+</resources>
diff --git a/java/com/android/voicemail/impl/configui/res/xml/vvm_config_override.xml b/java/com/android/voicemail/impl/configui/res/xml/vvm_config_override.xml
new file mode 100644
index 0000000..c4a23c7
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/res/xml/vvm_config_override.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <Preference
+ android:key="@string/vvm_config_override_load_current_key"
+ android:title="Load current"/>
+
+ <SwitchPreference
+ android:key="@string/vvm_config_override_enabled_key"
+ android:title="Override enabled"
+ android:defaultValue="false"/>
+
+ <!-- Keys should be a key in CarrierConfigManager prefixed with "vvm_config_override_key_" -->
+ <EditTextPreference
+ android:key="vvm_config_override_key_vvm_type_string"
+ android:title="type"
+ android:defaultValue="vvm_type_omtp"
+ />
+
+ <EditTextPreference
+ android:key="vvm_config_override_key_vvm_destination_number_string"
+ android:title="destination number"
+ />
+
+ <EditTextPreference
+ android:key="vvm_config_override_key_vvm_port_number_int"
+ android:title="destination port"
+ />
+ <EditTextPreference
+ android:key="vvm_config_override_key_carrier_vvm_package_name_string_array"
+ android:title="vvm package name (CSV)"
+ />
+
+ <SwitchPreference
+ android:key="vvm_config_override_key_vvm_prefetch_bool"
+ android:title="prefetch"
+ android:defaultValue="true"/>
+
+ <SwitchPreference
+ android:key="vvm_config_override_key_vvm_cellular_data_required_bool"
+ android:title="cellular data required"
+ android:defaultValue="false"/>
+ <EditTextPreference
+ android:key="vvm_config_override_key_vvm_ssl_port_number_int"
+ android:title="SSL port"
+ />
+
+ <SwitchPreference
+ android:key="vvm_config_override_key_vvm_legacy_mode_enabled_bool"
+ android:title="legacy mode"
+ android:defaultValue="false"/>
+
+ <EditTextPreference
+ android:key="vvm_config_override_key_vvm_disabled_capabilities_string_array"
+ android:title="disabled capabilities (CSV)"
+ />
+
+ <EditTextPreference
+ android:key="vvm_config_override_key_vvm_client_prefix_string"
+ android:title="client prefix"
+ />
+</PreferenceScreen>
\ No newline at end of file
diff --git a/java/com/android/voicemail/impl/mail/MailTransport.java b/java/com/android/voicemail/impl/mail/MailTransport.java
index 00339f0..c35e414 100644
--- a/java/com/android/voicemail/impl/mail/MailTransport.java
+++ b/java/com/android/voicemail/impl/mail/MailTransport.java
@@ -195,6 +195,8 @@
} catch (IOException ioe) {
LogUtils.d(TAG, ioe.toString());
throw new MessagingException(MessagingException.IOERROR, ioe.toString());
+ } finally {
+ TrafficStats.clearThreadStatsTag();
}
}
diff --git a/java/com/android/voicemail/impl/res/values/strings.xml b/java/com/android/voicemail/impl/res/values/strings.xml
index 375a1e9..a846541 100644
--- a/java/com/android/voicemail/impl/res/values/strings.xml
+++ b/java/com/android/voicemail/impl/res/values/strings.xml
@@ -107,4 +107,8 @@
<string name="change_pin_succeeded">Voicemail PIN updated</string>
<!-- The error message to show if the server reported an error while attempting to change the voicemail PIN -->
<string name="change_pin_system_error">Unable to set PIN</string>
+
+ <string name="vvm_config_override_load_current_key" translatable="false">vvm_config_override_load_current</string>
+ <string name="vvm_config_override_enabled_key" translatable="false">vvm_config_override_enabled</string>
+
</resources>
diff --git a/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java b/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java
index 1cf3737..4383527 100644
--- a/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java
+++ b/java/com/android/voicemail/impl/sms/OmtpMessageReceiver.java
@@ -35,7 +35,6 @@
import com.android.voicemail.impl.VvmLog;
import com.android.voicemail.impl.protocol.VisualVoicemailProtocol;
import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
-import com.android.voicemail.impl.sync.OmtpVvmSyncService;
import com.android.voicemail.impl.sync.SyncOneTask;
import com.android.voicemail.impl.sync.SyncTask;
import com.android.voicemail.impl.sync.VoicemailsQueryHelper;
@@ -152,7 +151,7 @@
}
break;
case OmtpConstants.MAILBOX_UPDATE:
- SyncTask.start(mContext, phone, OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY);
+ SyncTask.start(mContext, phone);
break;
case OmtpConstants.GREETINGS_UPDATE:
// Not implemented in V1
diff --git a/java/com/android/voicemail/impl/sync/OmtpVvmSyncReceiver.java b/java/com/android/voicemail/impl/sync/OmtpVvmSyncReceiver.java
index b2ec49e..1b59ecc 100644
--- a/java/com/android/voicemail/impl/sync/OmtpVvmSyncReceiver.java
+++ b/java/com/android/voicemail/impl/sync/OmtpVvmSyncReceiver.java
@@ -52,7 +52,7 @@
VvmLog.i(TAG, "Unactivated account " + phoneAccount + " found, activating");
ActivationTask.start(context, phoneAccount, null);
} else {
- SyncTask.start(context, phoneAccount, OmtpVvmSyncService.SYNC_FULL_SYNC);
+ SyncTask.start(context, phoneAccount);
}
}
}
diff --git a/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java b/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java
index 7933883..5b5d6b0 100644
--- a/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java
+++ b/java/com/android/voicemail/impl/sync/OmtpVvmSyncService.java
@@ -43,6 +43,7 @@
import com.android.voicemail.impl.sync.VvmNetworkRequest.RequestFailedException;
import com.android.voicemail.impl.utils.LoggerUtils;
import com.android.voicemail.impl.utils.VoicemailDatabaseUtil;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -50,22 +51,13 @@
@TargetApi(VERSION_CODES.O)
public class OmtpVvmSyncService {
- private static final String TAG = OmtpVvmSyncService.class.getSimpleName();
+ private static final String TAG = "OmtpVvmSyncService";
- /** Signifies a sync with both uploading to the server and downloading from the server. */
- public static final String SYNC_FULL_SYNC = "full_sync";
- /** Only upload to the server. */
- public static final String SYNC_UPLOAD_ONLY = "upload_only";
- /** Only download from the server. */
- public static final String SYNC_DOWNLOAD_ONLY = "download_only";
- /** Only download single voicemail transcription. */
- public static final String SYNC_DOWNLOAD_ONE_TRANSCRIPTION = "download_one_transcription";
/** Threshold for whether we should archive and delete voicemails from the remote VM server. */
private static final float AUTO_DELETE_ARCHIVE_VM_THRESHOLD = 0.75f;
private final Context mContext;
-
- private VoicemailsQueryHelper mQueryHelper;
+ private final VoicemailsQueryHelper mQueryHelper;
public OmtpVvmSyncService(Context context) {
mContext = context;
@@ -74,23 +66,21 @@
public void sync(
BaseTask task,
- String action,
PhoneAccountHandle phoneAccount,
Voicemail voicemail,
VoicemailStatus.Editor status) {
Assert.isTrue(phoneAccount != null);
- VvmLog.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount);
- setupAndSendRequest(task, phoneAccount, voicemail, action, status);
+ VvmLog.v(TAG, "Sync requested for account: " + phoneAccount);
+ setupAndSendRequest(task, phoneAccount, voicemail, status);
}
private void setupAndSendRequest(
BaseTask task,
PhoneAccountHandle phoneAccount,
Voicemail voicemail,
- String action,
VoicemailStatus.Editor status) {
if (!VisualVoicemailSettingsUtil.isEnabled(mContext, phoneAccount)) {
- VvmLog.v(TAG, "Sync requested for disabled account");
+ VvmLog.e(TAG, "Sync requested for disabled account");
return;
}
if (!VvmAccountManager.isAccountActivated(mContext, phoneAccount)) {
@@ -102,7 +92,7 @@
LoggerUtils.logImpressionOnMainThread(mContext, DialerImpression.Type.VVM_SYNC_STARTED);
// DATA_IMAP_OPERATION_STARTED posting should not be deferred. This event clears all data
// channel errors, which should happen when the task starts, not when it ends. It is the
- // "Sync in progress..." status.
+ // "Sync in progress..." status, which is currently displayed to the user as no error.
config.handleEvent(
VoicemailStatus.edit(mContext, phoneAccount), OmtpEvents.DATA_IMAP_OPERATION_STARTED);
try (NetworkWrapper network = VvmNetworkRequest.getNetwork(config, phoneAccount, status)) {
@@ -111,7 +101,7 @@
task.fail();
return;
}
- doSync(task, network.get(), phoneAccount, voicemail, action, status);
+ doSync(task, network.get(), phoneAccount, voicemail, status);
} catch (RequestFailedException e) {
config.handleEvent(status, OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED);
task.fail();
@@ -123,14 +113,13 @@
Network network,
PhoneAccountHandle phoneAccount,
Voicemail voicemail,
- String action,
VoicemailStatus.Editor status) {
try (ImapHelper imapHelper = new ImapHelper(mContext, phoneAccount, network, status)) {
boolean success;
if (voicemail == null) {
- success = syncAll(action, imapHelper, phoneAccount);
+ success = syncAll(imapHelper, phoneAccount);
} else {
- success = syncOne(imapHelper, voicemail, phoneAccount);
+ success = downloadOneVoicemail(imapHelper, voicemail, phoneAccount);
}
if (success) {
// TODO: b/30569269 failure should interrupt all subsequent task via exceptions
@@ -219,79 +208,33 @@
}
}
- private boolean syncAll(String action, ImapHelper imapHelper, PhoneAccountHandle account) {
- boolean uploadSuccess = true;
- boolean downloadSuccess = true;
+ private boolean syncAll(ImapHelper imapHelper, PhoneAccountHandle account) {
- if (SYNC_FULL_SYNC.equals(action) || SYNC_UPLOAD_ONLY.equals(action)) {
- uploadSuccess = upload(account, imapHelper);
- }
- if (SYNC_FULL_SYNC.equals(action) || SYNC_DOWNLOAD_ONLY.equals(action)) {
- downloadSuccess = download(imapHelper, account);
- }
-
- VvmLog.v(
- TAG,
- "upload succeeded: ["
- + String.valueOf(uploadSuccess)
- + "] download succeeded: ["
- + String.valueOf(downloadSuccess)
- + "]");
-
- return uploadSuccess && downloadSuccess;
- }
-
- private boolean syncOne(ImapHelper imapHelper, Voicemail voicemail, PhoneAccountHandle account) {
- if (shouldPerformPrefetch(account, imapHelper)) {
- VoicemailFetchedCallback callback =
- new VoicemailFetchedCallback(mContext, voicemail.getUri(), account);
- imapHelper.fetchVoicemailPayload(callback, voicemail.getSourceData());
- }
-
- return imapHelper.fetchTranscription(
- new TranscriptionFetchedCallback(mContext, voicemail), voicemail.getSourceData());
- }
-
- private boolean upload(PhoneAccountHandle phoneAccountHandle, ImapHelper imapHelper) {
- List<Voicemail> readVoicemails = mQueryHelper.getReadVoicemails(phoneAccountHandle);
- List<Voicemail> deletedVoicemails = mQueryHelper.getDeletedVoicemails(phoneAccountHandle);
-
- boolean success = true;
-
- if (deletedVoicemails.size() > 0) {
- if (imapHelper.markMessagesAsDeleted(deletedVoicemails)) {
- // We want to delete selectively instead of all the voicemails for this provider
- // in case the state changed since the IMAP query was completed.
- mQueryHelper.deleteFromDatabase(deletedVoicemails);
- } else {
- success = false;
- }
- }
-
- if (readVoicemails.size() > 0) {
- VvmLog.i(TAG, "Marking voicemails as read");
- if (imapHelper.markMessagesAsRead(readVoicemails)) {
- VvmLog.i(TAG, "Marking voicemails as clean");
- mQueryHelper.markCleanInDatabase(readVoicemails);
- } else {
- success = false;
- }
- }
-
- return success;
- }
-
- private boolean download(ImapHelper imapHelper, PhoneAccountHandle account) {
List<Voicemail> serverVoicemails = imapHelper.fetchAllVoicemails();
List<Voicemail> localVoicemails = mQueryHelper.getAllVoicemails(account);
+ List<Voicemail> deletedVoicemails = mQueryHelper.getDeletedVoicemails(account);
+ boolean succeeded = true;
if (localVoicemails == null || serverVoicemails == null) {
// Null value means the query failed.
+ VvmLog.e(TAG, "syncAll: query failed");
return false;
}
+ if (deletedVoicemails.size() > 0) {
+ if (imapHelper.markMessagesAsDeleted(deletedVoicemails)) {
+ // Delete only the voicemails that was deleted on the server, in case more are deleted
+ // since the IMAP query was completed.
+ mQueryHelper.deleteFromDatabase(deletedVoicemails);
+ } else {
+ succeeded = false;
+ }
+ }
+
Map<String, Voicemail> remoteMap = buildMap(serverVoicemails);
+ List<Voicemail> localReadVoicemails = new ArrayList<>();
+
// Go through all the local voicemails and check if they are on the server.
// They may be read or deleted on the server but not locally. Perform the
// appropriate local operation if the status differs from the server. Remove
@@ -310,6 +253,8 @@
} else {
if (remoteVoicemail.isRead() && !localVoicemail.isRead()) {
mQueryHelper.markReadInDatabase(localVoicemail);
+ } else if (localVoicemail.isRead() && !remoteVoicemail.isRead()) {
+ localReadVoicemails.add(localVoicemail);
}
if (!TextUtils.isEmpty(remoteVoicemail.getTranscription())
@@ -321,6 +266,16 @@
}
}
+ if (localReadVoicemails.size() > 0) {
+ VvmLog.i(TAG, "Marking voicemails as read");
+ if (imapHelper.markMessagesAsRead(localReadVoicemails)) {
+ VvmLog.i(TAG, "Marking voicemails as clean");
+ mQueryHelper.markCleanInDatabase(localReadVoicemails);
+ } else {
+ return false;
+ }
+ }
+
// The leftover messages are messages that exist on the server but not locally.
boolean prefetchEnabled = shouldPerformPrefetch(account, imapHelper);
for (Voicemail remoteVoicemail : remoteMap.values()) {
@@ -336,7 +291,19 @@
}
}
- return true;
+ return succeeded;
+ }
+
+ private boolean downloadOneVoicemail(
+ ImapHelper imapHelper, Voicemail voicemail, PhoneAccountHandle account) {
+ if (shouldPerformPrefetch(account, imapHelper)) {
+ VoicemailFetchedCallback callback =
+ new VoicemailFetchedCallback(mContext, voicemail.getUri(), account);
+ imapHelper.fetchVoicemailPayload(callback, voicemail.getSourceData());
+ }
+
+ return imapHelper.fetchTranscription(
+ new TranscriptionFetchedCallback(mContext, voicemail), voicemail.getSourceData());
}
private boolean shouldPerformPrefetch(PhoneAccountHandle account, ImapHelper imapHelper) {
diff --git a/java/com/android/voicemail/impl/sync/SyncOneTask.java b/java/com/android/voicemail/impl/sync/SyncOneTask.java
index cd2782a..70c6bd8 100644
--- a/java/com/android/voicemail/impl/sync/SyncOneTask.java
+++ b/java/com/android/voicemail/impl/sync/SyncOneTask.java
@@ -39,17 +39,14 @@
private static final int RETRY_INTERVAL_MILLIS = 5_000;
private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
- private static final String EXTRA_SYNC_TYPE = "extra_sync_type";
private static final String EXTRA_VOICEMAIL = "extra_voicemail";
private PhoneAccountHandle mPhone;
- private String mSyncType;
private Voicemail mVoicemail;
public static void start(Context context, PhoneAccountHandle phone, Voicemail voicemail) {
Intent intent = BaseTask.createIntent(context, SyncOneTask.class, phone);
intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone);
- intent.putExtra(EXTRA_SYNC_TYPE, OmtpVvmSyncService.SYNC_DOWNLOAD_ONE_TRANSCRIPTION);
intent.putExtra(EXTRA_VOICEMAIL, voicemail);
context.sendBroadcast(intent);
}
@@ -63,14 +60,13 @@
public void onCreate(Context context, Bundle extras) {
super.onCreate(context, extras);
mPhone = extras.getParcelable(EXTRA_PHONE_ACCOUNT_HANDLE);
- mSyncType = extras.getString(EXTRA_SYNC_TYPE);
mVoicemail = extras.getParcelable(EXTRA_VOICEMAIL);
}
@Override
public void onExecuteInBackgroundThread() {
OmtpVvmSyncService service = new OmtpVvmSyncService(getContext());
- service.sync(this, mSyncType, mPhone, mVoicemail, VoicemailStatus.edit(getContext(), mPhone));
+ service.sync(this, mPhone, mVoicemail, VoicemailStatus.edit(getContext(), mPhone));
}
@Override
@@ -78,7 +74,6 @@
LoggerUtils.logImpressionOnMainThread(getContext(), DialerImpression.Type.VVM_AUTO_RETRY_SYNC);
Intent intent = super.createRestartIntent();
intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone);
- intent.putExtra(EXTRA_SYNC_TYPE, mSyncType);
intent.putExtra(EXTRA_VOICEMAIL, mVoicemail);
return intent;
}
diff --git a/java/com/android/voicemail/impl/sync/SyncTask.java b/java/com/android/voicemail/impl/sync/SyncTask.java
index 0b3e090..68ce012 100644
--- a/java/com/android/voicemail/impl/sync/SyncTask.java
+++ b/java/com/android/voicemail/impl/sync/SyncTask.java
@@ -37,17 +37,14 @@
private static final int MINIMAL_INTERVAL_MILLIS = 60_000;
private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
- private static final String EXTRA_SYNC_TYPE = "extra_sync_type";
private final RetryPolicy mRetryPolicy;
private PhoneAccountHandle mPhone;
- private String mSyncType;
- public static void start(Context context, PhoneAccountHandle phone, String syncType) {
+ public static void start(Context context, PhoneAccountHandle phone) {
Intent intent = BaseTask.createIntent(context, SyncTask.class, phone);
intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone);
- intent.putExtra(EXTRA_SYNC_TYPE, syncType);
context.sendBroadcast(intent);
}
@@ -62,13 +59,12 @@
public void onCreate(Context context, Bundle extras) {
super.onCreate(context, extras);
mPhone = extras.getParcelable(EXTRA_PHONE_ACCOUNT_HANDLE);
- mSyncType = extras.getString(EXTRA_SYNC_TYPE);
}
@Override
public void onExecuteInBackgroundThread() {
OmtpVvmSyncService service = new OmtpVvmSyncService(getContext());
- service.sync(this, mSyncType, mPhone, null, mRetryPolicy.getVoicemailStatusEditor());
+ service.sync(this, mPhone, null, mRetryPolicy.getVoicemailStatusEditor());
}
@Override
@@ -76,7 +72,6 @@
LoggerUtils.logImpressionOnMainThread(getContext(), DialerImpression.Type.VVM_AUTO_RETRY_SYNC);
Intent intent = super.createRestartIntent();
intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone);
- intent.putExtra(EXTRA_SYNC_TYPE, mSyncType);
return intent;
}
}
diff --git a/java/com/android/voicemail/impl/sync/UploadTask.java b/java/com/android/voicemail/impl/sync/UploadTask.java
index f2b2036..d8f06db 100644
--- a/java/com/android/voicemail/impl/sync/UploadTask.java
+++ b/java/com/android/voicemail/impl/sync/UploadTask.java
@@ -63,10 +63,6 @@
return;
}
service.sync(
- this,
- OmtpVvmSyncService.SYNC_UPLOAD_ONLY,
- phoneAccountHandle,
- null,
- VoicemailStatus.edit(getContext(), phoneAccountHandle));
+ this, phoneAccountHandle, null, VoicemailStatus.edit(getContext(), phoneAccountHandle));
}
}
diff --git a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java
index 9b295db..316e1ca 100644
--- a/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java
+++ b/java/com/android/voicemail/impl/sync/VoicemailsQueryHelper.java
@@ -49,8 +49,6 @@
public static final int DELETED = 3;
public static final int TRANSCRIPTION = 4;
- static final String READ_SELECTION =
- Voicemails.DIRTY + "=1 AND " + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1";
static final String DELETED_SELECTION = Voicemails.DELETED + "=1";
static final String ARCHIVED_SELECTION = Voicemails.ARCHIVED + "=0";
@@ -65,15 +63,6 @@
}
/**
- * Get all the local read voicemails that have not been synced to the server.
- *
- * @return A list of read voicemails.
- */
- public List<Voicemail> getReadVoicemails(@NonNull PhoneAccountHandle phoneAccountHandle) {
- return getLocalVoicemails(phoneAccountHandle, READ_SELECTION);
- }
-
- /**
* Get all the locally deleted voicemails that have not been synced to the server.
*
* @return A list of deleted voicemails.
diff --git a/java/com/android/voicemail/stub/StubVoicemailClient.java b/java/com/android/voicemail/stub/StubVoicemailClient.java
index e2b4707..e5d5145 100644
--- a/java/com/android/voicemail/stub/StubVoicemailClient.java
+++ b/java/com/android/voicemail/stub/StubVoicemailClient.java
@@ -18,6 +18,9 @@
import android.content.Context;
import android.content.Intent;
+import android.os.PersistableBundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import com.android.voicemail.VoicemailClient;
@@ -81,4 +84,19 @@
public boolean isActivated(Context context, PhoneAccountHandle phoneAccountHandle) {
return false;
}
+
+ @Override
+ public void showConfigUi(@NonNull Context context) {}
+
+ @Override
+ public PersistableBundle getConfig(
+ @NonNull Context context, @Nullable PhoneAccountHandle phoneAccountHandle) {
+ return new PersistableBundle();
+ }
+
+ @Override
+ public void onBoot(@NonNull Context context) {}
+
+ @Override
+ public void onShutdown(@NonNull Context context) {}
}