From e39af763e7bf598306feab4a3d2e1164c9f0421a Mon Sep 17 00:00:00 2001 From: linyuh Date: Fri, 27 Oct 2017 14:19:14 -0700 Subject: Make dialpad key alignment responsive to font size. In portrait mode, we surround the icon and letters with a linear layout so that we can adjust its height. In landscape mode, we add a horizontal placeholder to each key's layout so that we can adjust its width. This approach was put forward by Ryan Oldenburg (roldenburg@). Bug: 30215380 Test: Manual PiperOrigin-RevId: 173717443 Change-Id: I9b60657ca20d371a60c303a9683578663fc28a09 --- .../android/dialer/dialpadview/DialpadView.java | 177 ++++++++++++++++----- .../dialpadview/res/layout-land/dialpad_key.xml | 23 ++- .../res/layout-land/dialpad_key_one.xml | 20 ++- .../res/layout-land/dialpad_key_pound.xml | 9 +- .../res/layout-land/dialpad_key_star.xml | 9 +- .../res/layout-land/dialpad_key_zero.xml | 9 +- .../dialer/dialpadview/res/layout/dialpad_key.xml | 28 ++-- .../dialpadview/res/layout/dialpad_key_one.xml | 49 +++--- .../dialpadview/res/layout/dialpad_key_pound.xml | 17 +- .../dialpadview/res/layout/dialpad_key_star.xml | 17 +- .../dialpadview/res/layout/dialpad_key_zero.xml | 25 ++- 11 files changed, 271 insertions(+), 112 deletions(-) diff --git a/java/com/android/dialer/dialpadview/DialpadView.java b/java/com/android/dialer/dialpadview/DialpadView.java index 0c53273a4..d70b0a6c2 100644 --- a/java/com/android/dialer/dialpadview/DialpadView.java +++ b/java/com/android/dialer/dialpadview/DialpadView.java @@ -39,6 +39,7 @@ import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import com.android.dialer.animation.AnimUtils; +import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; import java.text.DecimalFormat; @@ -50,16 +51,13 @@ public class DialpadView extends LinearLayout { private static final String TAG = DialpadView.class.getSimpleName(); + // Parameters for animation private static final double DELAY_MULTIPLIER = 0.66; private static final double DURATION_MULTIPLIER = 0.8; - // For animation. private static final int KEY_FRAME_DURATION = 33; - /** {@code True} if the dialpad is in landscape orientation. */ - private final boolean mIsLandscape; - /** {@code True} if the dialpad is showing in a right-to-left locale. */ - private final boolean mIsRtl; - private final int[] mButtonIds = + // Resource IDs for buttons (0-9, *, and #) + private static final int[] BUTTON_IDS = new int[] { R.id.zero, R.id.one, @@ -74,6 +72,30 @@ public class DialpadView extends LinearLayout { R.id.star, R.id.pound }; + + // Resource IDs for the button-letter mapping + private static final int[] LETTER_MAPPING_IDS = + new int[] { + R.string.dialpad_0_letters, + R.string.dialpad_1_letters, + R.string.dialpad_2_letters, + R.string.dialpad_3_letters, + R.string.dialpad_4_letters, + R.string.dialpad_5_letters, + R.string.dialpad_6_letters, + R.string.dialpad_7_letters, + R.string.dialpad_8_letters, + R.string.dialpad_9_letters, + R.string.dialpad_star_letters, + R.string.dialpad_pound_letters + }; + + // Whether the device is in landscape mode + private final boolean mIsLandscape; + + // Whether the dialpad is shown in a right-to-left locale + private final boolean mIsRtl; + private EditText mDigits; private ImageButton mDelete; private View mOverflowMenuButton; @@ -110,6 +132,8 @@ public class DialpadView extends LinearLayout { @Override protected void onFinishInflate() { + super.onFinishInflate(); + setupKeypad(); mDigits = (EditText) findViewById(R.id.digits); mDelete = (ImageButton) findViewById(R.id.deleteButton); @@ -127,28 +151,8 @@ public class DialpadView extends LinearLayout { } private void setupKeypad() { - final int[] letterIds = - new int[] { - R.string.dialpad_0_letters, - R.string.dialpad_1_letters, - R.string.dialpad_2_letters, - R.string.dialpad_3_letters, - R.string.dialpad_4_letters, - R.string.dialpad_5_letters, - R.string.dialpad_6_letters, - R.string.dialpad_7_letters, - R.string.dialpad_8_letters, - R.string.dialpad_9_letters, - R.string.dialpad_star_letters, - R.string.dialpad_pound_letters - }; - final Resources resources = getContext().getResources(); - DialpadKeyButton dialpadKey; - TextView numberView; - TextView lettersView; - final Locale currentLocale = resources.getConfiguration().locale; final NumberFormat nf; // We translate dialpad numbers only for "fa" and not any other locale @@ -159,17 +163,16 @@ public class DialpadView extends LinearLayout { nf = DecimalFormat.getInstance(Locale.ENGLISH); } - for (int i = 0; i < mButtonIds.length; i++) { - dialpadKey = (DialpadKeyButton) findViewById(mButtonIds[i]); - numberView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_number); - lettersView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_letters); + for (int i = 0; i < BUTTON_IDS.length; i++) { + DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(BUTTON_IDS[i]); + TextView numberView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_number); final String numberString; final CharSequence numberContentDescription; - if (mButtonIds[i] == R.id.pound) { + if (BUTTON_IDS[i] == R.id.pound) { numberString = resources.getString(R.string.dialpad_pound_number); numberContentDescription = numberString; - } else if (mButtonIds[i] == R.id.star) { + } else if (BUTTON_IDS[i] == R.id.star) { numberString = resources.getString(R.string.dialpad_star_number); numberContentDescription = numberString; } else { @@ -177,7 +180,7 @@ public class DialpadView extends LinearLayout { // The content description is used for Talkback key presses. The number is // separated by a "," to introduce a slight delay. Convert letters into a verbatim // span so that they are read as letters instead of as one word. - String letters = resources.getString(letterIds[i]); + String letters = resources.getString(LETTER_MAPPING_IDS[i]); Spannable spannable = Spannable.Factory.getInstance().newSpannable(numberString + "," + letters); spannable.setSpan( @@ -199,8 +202,9 @@ public class DialpadView extends LinearLayout { dialpadKey.setContentDescription(numberContentDescription); dialpadKey.setBackground(rippleBackground); + TextView lettersView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_letters); if (lettersView != null) { - lettersView.setText(resources.getString(letterIds[i])); + lettersView.setText(resources.getString(LETTER_MAPPING_IDS[i])); } } @@ -211,6 +215,103 @@ public class DialpadView extends LinearLayout { zero.setLongHoverContentDescription(resources.getText(R.string.description_image_button_plus)); } + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + if (changed) { + if (mIsLandscape) { + adjustKeyWidths(); + } else { + adjustKeyHeightsInFirstRow(); + } + } + } + + /** + * Adjust key heights in the first row. + * + *

A voice mail icon is shown under key "1", which makes its height different from other keys + * in the first row. + * + *

This method should be called after the sizes of related layouts have been calculated by the + * framework. + */ + private void adjustKeyHeightsInFirstRow() { + int maxHeight = 0; + for (int i = 1; i <= 3; i++) { + DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(BUTTON_IDS[i]); + LinearLayout keyLayout = (LinearLayout) dialpadKey.findViewById(R.id.dialpad_key_layout); + maxHeight = Math.max(maxHeight, keyLayout.getHeight()); + } + + for (int i = 1; i <= 3; i++) { + DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(BUTTON_IDS[i]); + LinearLayout keyLayout = (LinearLayout) dialpadKey.findViewById(R.id.dialpad_key_layout); + + DialpadTextView numberView = + (DialpadTextView) keyLayout.findViewById(R.id.dialpad_key_number); + MarginLayoutParams numberViewLayoutParams = (MarginLayoutParams) numberView.getLayoutParams(); + + LinearLayout iconOrLettersLayout = + (LinearLayout) keyLayout.findViewById(R.id.dialpad_key_icon_or_letters_layout); + iconOrLettersLayout.setLayoutParams( + new LayoutParams( + LayoutParams.WRAP_CONTENT /* width */, + maxHeight + - numberView.getHeight() + - numberViewLayoutParams.topMargin + - numberViewLayoutParams.bottomMargin /* height */)); + } + } + + /** + * Adjust key widths to align keys in each column. + * + *

When the device is in landscape mode, we first find the maximum among a pre-defined width + * and the width of each key layout. Then we adjust the width of each layout's horizontal + * placeholder to align keys in each column. This is to accommodate the scenario where not all + * letters associated with a key can be displayed in one line due to large font size. + * + *

This method should be called after the sizes of related layouts have been calculated by the + * framework. + */ + private void adjustKeyWidths() { + Assert.checkState(mIsLandscape); + + // A pre-defined minimum width for the letters shown beside a key. + final int minimumKeyLettersWidth = + getContext().getResources().getDimensionPixelSize(R.dimen.dialpad_key_text_width); + + // The maximum width of the key layouts. A key layout includes both the number and the letters. + int maxWidth = 0; + + for (int buttonId : BUTTON_IDS) { + DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(buttonId); + LinearLayout keyLayout = (LinearLayout) dialpadKey.findViewById(R.id.dialpad_key_layout); + TextView keyLettersView = (TextView) keyLayout.findViewById(R.id.dialpad_key_letters); + if (keyLettersView != null && keyLettersView.getWidth() < minimumKeyLettersWidth) { + // If the width of the letters is less than the pre-defined minimum, use the pre-defined + // minimum to obtain the maximum width. + maxWidth = + Math.max( + maxWidth, + keyLayout.getWidth() - keyLettersView.getWidth() + minimumKeyLettersWidth); + } else { + maxWidth = Math.max(maxWidth, keyLayout.getWidth()); + } + } + + for (int buttonId : BUTTON_IDS) { + DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(buttonId); + LinearLayout keyLayout = (LinearLayout) dialpadKey.findViewById(R.id.dialpad_key_layout); + View horizontalPlaceholder = keyLayout.findViewById(R.id.dialpad_key_horizontal_placeholder); + horizontalPlaceholder.setLayoutParams( + new LayoutParams( + maxWidth - keyLayout.getWidth() /* width */, LayoutParams.MATCH_PARENT /* height */)); + } + } + private Drawable getDrawableCompat(Context context, int id) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return context.getDrawable(id); @@ -275,10 +376,10 @@ public class DialpadView extends LinearLayout { // numbers appear at their original position (0) momentarily before animating. final AnimatorListenerAdapter showListener = new AnimatorListenerAdapter() {}; - for (int i = 0; i < mButtonIds.length; i++) { - int delay = (int) (getKeyButtonAnimationDelay(mButtonIds[i]) * DELAY_MULTIPLIER); - int duration = (int) (getKeyButtonAnimationDuration(mButtonIds[i]) * DURATION_MULTIPLIER); - final DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(mButtonIds[i]); + for (int i = 0; i < BUTTON_IDS.length; i++) { + int delay = (int) (getKeyButtonAnimationDelay(BUTTON_IDS[i]) * DELAY_MULTIPLIER); + int duration = (int) (getKeyButtonAnimationDuration(BUTTON_IDS[i]) * DURATION_MULTIPLIER); + final DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(BUTTON_IDS[i]); ViewPropertyAnimator animator = dialpadKey.animate(); if (mIsLandscape) { diff --git a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key.xml b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key.xml index b126f723f..12f24ac52 100644 --- a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key.xml +++ b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key.xml @@ -14,12 +14,13 @@ limitations under the License. --> - + - + + + + + + + + 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 5023413ae..2f2e725d5 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 @@ -13,12 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. --> + + - + + - + + + + + diff --git a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_pound.xml b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_pound.xml index a3e0c7c14..613e73108 100644 --- a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_pound.xml +++ b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_pound.xml @@ -13,12 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. --> + + + + android:id="@+id/dialpad_key_horizontal_placeholder" + android:layout_width="0dp" + android:layout_height="match_parent"/> diff --git a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_star.xml b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_star.xml index 18dc1cb49..2b0a6b554 100644 --- a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_star.xml +++ b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_star.xml @@ -13,12 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. --> + + + + android:id="@+id/dialpad_key_horizontal_placeholder" + android:layout_width="0dp" + android:layout_height="match_parent"/> diff --git a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_zero.xml b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_zero.xml index 4c46447d4..714507202 100644 --- a/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_zero.xml +++ b/java/com/android/dialer/dialpadview/res/layout-land/dialpad_key_zero.xml @@ -21,6 +21,7 @@ style="@style/DialpadKeyButtonStyle"> + style="@style/DialpadKeyLettersStyle"/> + + diff --git a/java/com/android/dialer/dialpadview/res/layout/dialpad_key.xml b/java/com/android/dialer/dialpadview/res/layout/dialpad_key.xml index 77e4fc53a..6c87cd2b4 100644 --- a/java/com/android/dialer/dialpadview/res/layout/dialpad_key.xml +++ b/java/com/android/dialer/dialpadview/res/layout/dialpad_key.xml @@ -14,22 +14,26 @@ limitations under the License. --> - + + xmlns:android="http://schemas.android.com/apk/res/android" + style="@style/DialpadKeyButtonStyle"> - - - + + android:id="@+id/dialpad_key_number" + style="@style/DialpadKeyNumberStyle"/> + + - + + 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 4401c5bbd..599c2d8e6 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 @@ -13,29 +13,40 @@ See the License for the specific language governing permissions and limitations under the License. --> + + + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/one" + style="@style/DialpadKeyButtonStyle"> + + - + android:id="@+id/dialpad_key_number" + style="@style/DialpadKeyNumberStyle"/> + + + + + + - - - + android:id="@+id/dialpad_key_voicemail" + android:layout_width="wrap_content" + android:layout_height="@dimen/dialpad_voicemail_icon_size" + 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/layout/dialpad_key_pound.xml b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_pound.xml index d37a6aa78..5e47ac092 100644 --- a/java/com/android/dialer/dialpadview/res/layout/dialpad_key_pound.xml +++ b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_pound.xml @@ -13,14 +13,19 @@ See the License for the specific language governing permissions and limitations under the License. --> + + + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/pound" + style="@style/DialpadKeyButtonStyle"> + + android:id="@+id/dialpad_key_layout" + style="@style/DialpadKeyInternalLayoutStyle"> + + android:id="@id/dialpad_key_number" + style="@style/DialpadKeyPoundStyle"/> diff --git a/java/com/android/dialer/dialpadview/res/layout/dialpad_key_star.xml b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_star.xml index d288475d0..6897d26e7 100644 --- a/java/com/android/dialer/dialpadview/res/layout/dialpad_key_star.xml +++ b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_star.xml @@ -13,14 +13,19 @@ See the License for the specific language governing permissions and limitations under the License. --> + + + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/star" + style="@style/DialpadKeyButtonStyle"> + + android:id="@+id/dialpad_key_layout" + style="@style/DialpadKeyInternalLayoutStyle"> + + android:id="@+id/dialpad_key_number" + style="@style/DialpadKeyStarStyle"/> diff --git a/java/com/android/dialer/dialpadview/res/layout/dialpad_key_zero.xml b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_zero.xml index 943ae48dd..8d9c7b216 100644 --- a/java/com/android/dialer/dialpadview/res/layout/dialpad_key_zero.xml +++ b/java/com/android/dialer/dialpadview/res/layout/dialpad_key_zero.xml @@ -14,24 +14,21 @@ limitations under the License. --> - + + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/zero" + style="@style/DialpadKeyButtonStyle"> - - - + - + android:id="@+id/dialpad_key_number" + style="@style/DialpadBottomKeyNumberStyle"/> + android:id="@+id/dialpad_key_letters" + style="@style/DialpadKeyLettersStyle"/> -- cgit v1.2.3 From ec1a970dec22d68773f8ae9dbde6f17df6154e03 Mon Sep 17 00:00:00 2001 From: mdooley Date: Fri, 27 Oct 2017 16:20:32 -0700 Subject: internal change Bug: 62423454 Test: manual and updated unit test PiperOrigin-RevId: 173731907 Change-Id: Ic73600197b1c4fa6ac0937a8c38b048cd8faded8 --- java/com/android/voicemail/VoicemailClient.java | 10 ++++++ .../voicemail/impl/VoicemailClientImpl.java | 25 ++++++++++++++ .../impl/fetch/VoicemailFetchedCallback.java | 3 +- .../android/voicemail/impl/res/values/strings.xml | 17 ++++++++++ .../voicemail/impl/res/xml/voicemail_settings.xml | 6 ++++ .../impl/settings/VisualVoicemailSettingsUtil.java | 21 ++++++++++++ .../impl/settings/VoicemailSettingsFragment.java | 38 ++++++++++++++++++++++ .../transcribe/TranscriptionBackfillService.java | 2 +- .../transcribe/TranscriptionConfigProvider.java | 5 +++ .../impl/transcribe/TranscriptionService.java | 22 ++++++++++--- .../impl/transcribe/TranscriptionTask.java | 22 ++++++++++--- .../impl/transcribe/TranscriptionTaskAsync.java | 13 +++++++- .../voicemail/stub/StubVoicemailClient.java | 10 ++++++ 13 files changed, 183 insertions(+), 11 deletions(-) diff --git a/java/com/android/voicemail/VoicemailClient.java b/java/com/android/voicemail/VoicemailClient.java index d52a67a8e..717362e18 100644 --- a/java/com/android/voicemail/VoicemailClient.java +++ b/java/com/android/voicemail/VoicemailClient.java @@ -124,6 +124,16 @@ public interface VoicemailClient { void setVoicemailArchiveEnabled( Context context, PhoneAccountHandle phoneAccountHandle, boolean value); + /** + * @return if the voicemail transcription feature is available on the current device. This depends + * on whether the server side flag is turned on for the feature, and if the OS meets the + * requirement for this feature. + */ + boolean isVoicemailTranscriptionAvailable(Context context); + + /** @return if the voicemail donation setting has been enabled by the user. */ + boolean isVoicemailDonationEnabled(Context context, PhoneAccountHandle account); + /** * @return an intent that will launch the activity to change the voicemail PIN. The PIN is used * when calling into the mailbox. diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java index 9bb14f2dc..ff1a18d32 100644 --- a/java/com/android/voicemail/impl/VoicemailClientImpl.java +++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java @@ -37,6 +37,7 @@ import com.android.voicemail.impl.settings.VoicemailChangePinActivity; import com.android.voicemail.impl.settings.VoicemailSettingsFragment; import com.android.voicemail.impl.sync.VvmAccountManager; import com.android.voicemail.impl.transcribe.TranscriptionBackfillService; +import com.android.voicemail.impl.transcribe.TranscriptionConfigProvider; import java.util.List; import javax.inject.Inject; @@ -119,6 +120,30 @@ public class VoicemailClientImpl implements VoicemailClient { VisualVoicemailSettingsUtil.setArchiveEnabled(context, phoneAccountHandle, value); } + @Override + public boolean isVoicemailTranscriptionAvailable(Context context) { + if (!BuildCompat.isAtLeastO()) { + LogUtil.i( + "VoicemailClientImpl.isVoicemailTranscriptionAvailable", "not running on O or later"); + return false; + } + + TranscriptionConfigProvider provider = new TranscriptionConfigProvider(context); + if (!provider.isVoicemailTranscriptionEnabled()) { + LogUtil.i( + "VoicemailClientImpl.isVoicemailTranscriptionAvailable", "feature disabled by config"); + return false; + } + + return true; + } + + @Override + public boolean isVoicemailDonationEnabled(Context context, PhoneAccountHandle account) { + return isVoicemailTranscriptionAvailable(context) + && VisualVoicemailSettingsUtil.isVoicemailDonationEnabled(context, account); + } + @Override public Intent getSetPinIntent(Context context, PhoneAccountHandle phoneAccountHandle) { Intent intent = new Intent(context, VoicemailChangePinActivity.class); diff --git a/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java b/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java index 3e825407b..e8e14bedb 100644 --- a/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java +++ b/java/com/android/voicemail/impl/fetch/VoicemailFetchedCallback.java @@ -97,7 +97,8 @@ public class VoicemailFetchedCallback { if (updateVoicemail(values)) { ThreadUtil.postOnUiThread( () -> { - if (!TranscriptionService.scheduleNewVoicemailTranscriptionJob(mContext, mUri, true)) { + if (!TranscriptionService.scheduleNewVoicemailTranscriptionJob( + mContext, mUri, mPhoneAccountHandle, true)) { VvmLog.w(TAG, String.format("Failed to schedule transcription for %s", mUri)); } }); diff --git a/java/com/android/voicemail/impl/res/values/strings.xml b/java/com/android/voicemail/impl/res/values/strings.xml index 66c0e62b0..c70306d0d 100644 --- a/java/com/android/voicemail/impl/res/values/strings.xml +++ b/java/com/android/voicemail/impl/res/values/strings.xml @@ -42,6 +42,9 @@ archive_is_enabled + + donate_voicemails + voicemail_change_pin_key @@ -53,6 +56,20 @@ Extra backup and storage + + + Voicemail transcription analysis + + + Visual voicemail must be enabled to donate voicemails + + Visual voicemail is not activated yet, please try again later + + Let Google review your voicemail messages to improve transcription quality + Set PIN diff --git a/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml b/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml index 50510905c..9b0391ad4 100644 --- a/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml +++ b/java/com/android/voicemail/impl/res/xml/voicemail_settings.xml @@ -29,6 +29,12 @@ android:key="@string/voicemail_visual_voicemail_archive_key" android:dependency="@string/voicemail_visual_voicemail_key" android:title="@string/voicemail_visual_voicemail_auto_archive_switch_title"/>" + + " + diff --git a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java index ae526d168..6694a5db8 100644 --- a/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java +++ b/java/com/android/voicemail/impl/settings/VisualVoicemailSettingsUtil.java @@ -57,6 +57,18 @@ public class VisualVoicemailSettingsUtil { .apply(); } + public static void setVoicemailDonationEnabled( + Context context, PhoneAccountHandle phoneAccount, boolean isEnabled) { + Assert.checkArgument( + VoicemailComponent.get(context) + .getVoicemailClient() + .isVoicemailTranscriptionAvailable(context)); + new VisualVoicemailPreferences(context, phoneAccount) + .edit() + .putBoolean(context.getString(R.string.voicemail_visual_voicemail_donation_key), isEnabled) + .apply(); + } + public static boolean isEnabled(Context context, PhoneAccountHandle phoneAccount) { if (phoneAccount == null) { return false; @@ -79,6 +91,15 @@ public class VisualVoicemailSettingsUtil { context.getString(R.string.voicemail_visual_voicemail_archive_key), false); } + public static boolean isVoicemailDonationEnabled( + Context context, PhoneAccountHandle phoneAccount) { + Assert.isNotNull(phoneAccount); + + VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount); + return prefs.getBoolean( + context.getString(R.string.voicemail_visual_voicemail_donation_key), false); + } + /** * Whether the client enabled status is explicitly set by user or by default(Whether carrier VVM * app is installed). This is used to determine whether to disable the client when the carrier VVM diff --git a/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java b/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java index e2ea72569..465223811 100644 --- a/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java +++ b/java/com/android/voicemail/impl/settings/VoicemailSettingsFragment.java @@ -53,6 +53,7 @@ public class VoicemailSettingsFragment extends PreferenceFragment private Preference voicemailNotificationPreference; private SwitchPreference voicemailVisualVoicemail; private SwitchPreference autoArchiveSwitchPreference; + private SwitchPreference donateVoicemailSwitchPreference; private Preference voicemailChangePinPreference; private PreferenceScreen advancedSettings; @@ -102,12 +103,22 @@ public class VoicemailSettingsFragment extends PreferenceFragment (SwitchPreference) findPreference(getString(R.string.voicemail_visual_voicemail_archive_key)); + donateVoicemailSwitchPreference = + (SwitchPreference) + findPreference(getString(R.string.voicemail_visual_voicemail_donation_key)); + if (!VoicemailComponent.get(getContext()) .getVoicemailClient() .isVoicemailArchiveAvailable(getContext())) { getPreferenceScreen().removePreference(autoArchiveSwitchPreference); } + if (!VoicemailComponent.get(getContext()) + .getVoicemailClient() + .isVoicemailDonationEnabled(getContext(), phoneAccountHandle)) { + getPreferenceScreen().removePreference(donateVoicemailSwitchPreference); + } + voicemailChangePinPreference = findPreference(getString(R.string.voicemail_change_pin_key)); if (omtpVvmCarrierConfigHelper.isValid()) { @@ -141,9 +152,15 @@ public class VoicemailSettingsFragment extends PreferenceFragment autoArchiveSwitchPreference.setOnPreferenceChangeListener(this); autoArchiveSwitchPreference.setChecked( VisualVoicemailSettingsUtil.isArchiveEnabled(getContext(), phoneAccountHandle)); + + donateVoicemailSwitchPreference.setOnPreferenceChangeListener(this); + donateVoicemailSwitchPreference.setChecked( + VisualVoicemailSettingsUtil.isVoicemailDonationEnabled(getContext(), phoneAccountHandle)); + updateDonateVoicemail(); } else { prefSet.removePreference(voicemailVisualVoicemail); prefSet.removePreference(autoArchiveSwitchPreference); + prefSet.removePreference(donateVoicemailSwitchPreference); prefSet.removePreference(voicemailChangePinPreference); } @@ -192,10 +209,15 @@ public class VoicemailSettingsFragment extends PreferenceFragment } updateChangePin(); + updateDonateVoicemail(); } else if (preference.getKey().equals(autoArchiveSwitchPreference.getKey())) { logArchiveToggle((boolean) objValue); VisualVoicemailSettingsUtil.setArchiveEnabled( getContext(), phoneAccountHandle, (boolean) objValue); + } else if (preference.getKey().equals(donateVoicemailSwitchPreference.getKey())) { + logArchiveToggle((boolean) objValue); + VisualVoicemailSettingsUtil.setVoicemailDonationEnabled( + getContext(), phoneAccountHandle, (boolean) objValue); } // Always let the preference setting proceed. @@ -217,6 +239,21 @@ public class VoicemailSettingsFragment extends PreferenceFragment } } + private void updateDonateVoicemail() { + if (!VisualVoicemailSettingsUtil.isEnabled(getContext(), phoneAccountHandle)) { + donateVoicemailSwitchPreference.setSummary( + R.string.voicemail_donate_preference_summary_disable); + donateVoicemailSwitchPreference.setEnabled(false); + } else if (!VvmAccountManager.isAccountActivated(getContext(), phoneAccountHandle)) { + donateVoicemailSwitchPreference.setSummary( + R.string.voicemail_donate_preference_summary_not_activated); + donateVoicemailSwitchPreference.setEnabled(false); + } else { + donateVoicemailSwitchPreference.setSummary(R.string.voicemail_donate_preference_summary_info); + donateVoicemailSwitchPreference.setEnabled(true); + } + } + private void logArchiveToggle(boolean userTurnedOn) { if (userTurnedOn) { Logger.get(getContext()) @@ -231,6 +268,7 @@ public class VoicemailSettingsFragment extends PreferenceFragment public void onActivationStateChanged(PhoneAccountHandle phoneAccountHandle, boolean isActivated) { if (this.phoneAccountHandle.equals(phoneAccountHandle)) { updateChangePin(); + updateDonateVoicemail(); } } diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java index f3c6e64f4..f7f643932 100644 --- a/java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java +++ b/java/com/android/voicemail/impl/transcribe/TranscriptionBackfillService.java @@ -72,7 +72,7 @@ public class TranscriptionBackfillService extends JobIntentService { for (Uri uri : untranscribed) { ThreadUtil.postOnUiThread( () -> { - TranscriptionService.scheduleNewVoicemailTranscriptionJob(this, uri, false); + TranscriptionService.scheduleNewVoicemailTranscriptionJob(this, uri, null, false); }); } } diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java b/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java index 4bb9a261b..5da450312 100644 --- a/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java +++ b/java/com/android/voicemail/impl/transcribe/TranscriptionConfigProvider.java @@ -75,6 +75,11 @@ public class TranscriptionConfigProvider { .getLong("voicemail_transcription_get_transcript_poll_interval_millis", 1000L); } + public boolean isVoicemailDonationEnabled() { + return ConfigProviderBindings.get(context) + .getBoolean("voicemail_transcription_donation_enabled", false); + } + @Override public String toString() { return String.format( diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java index b733928d7..79e1a017c 100644 --- a/java/com/android/voicemail/impl/transcribe/TranscriptionService.java +++ b/java/com/android/voicemail/impl/transcribe/TranscriptionService.java @@ -25,8 +25,10 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.support.annotation.MainThread; +import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.support.v4.os.BuildCompat; +import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; @@ -44,6 +46,7 @@ import java.util.concurrent.Executors; */ public class TranscriptionService extends JobService { @VisibleForTesting static final String EXTRA_VOICEMAIL_URI = "extra_voicemail_uri"; + @VisibleForTesting static final String EXTRA_ACCOUNT_HANDLE = "extra_account_handle"; private ExecutorService executorService; private JobParameters jobParameters; @@ -58,10 +61,14 @@ public class TranscriptionService extends JobService { } // Schedule a task to transcribe the indicated voicemail, return true if transcription task was - // scheduled. + // scheduled. If the PhoneAccountHandle is null then the voicemail will not be considered for + // donation. @MainThread public static boolean scheduleNewVoicemailTranscriptionJob( - Context context, Uri voicemailUri, boolean highPriority) { + Context context, + Uri voicemailUri, + @Nullable PhoneAccountHandle account, + boolean highPriority) { Assert.isMainThread(); if (BuildCompat.isAtLeastO()) { LogUtil.i( @@ -80,7 +87,7 @@ public class TranscriptionService extends JobService { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); } JobScheduler scheduler = context.getSystemService(JobScheduler.class); - JobWorkItem workItem = makeWorkItem(voicemailUri); + JobWorkItem workItem = makeWorkItem(voicemailUri, account); return scheduler.enqueue(builder.build(), workItem) == JobScheduler.RESULT_SUCCESS; } else { LogUtil.i("TranscriptionService.scheduleNewVoicemailTranscriptionJob", "not supported"); @@ -193,6 +200,10 @@ public class TranscriptionService extends JobService { return workItem.getIntent().getParcelableExtra(EXTRA_VOICEMAIL_URI); } + static PhoneAccountHandle getPhoneAccountHandle(JobWorkItem workItem) { + return workItem.getIntent().getParcelableExtra(EXTRA_ACCOUNT_HANDLE); + } + private ExecutorService getExecutorService() { if (executorService == null) { // The common use case is transcribing a single voicemail so just use a single thread executor @@ -219,9 +230,12 @@ public class TranscriptionService extends JobService { } } - private static JobWorkItem makeWorkItem(Uri voicemailUri) { + private static JobWorkItem makeWorkItem(Uri voicemailUri, PhoneAccountHandle account) { Intent intent = new Intent(); intent.putExtra(EXTRA_VOICEMAIL_URI, voicemailUri); + if (account != null) { + intent.putExtra(EXTRA_ACCOUNT_HANDLE, account); + } return new JobWorkItem(intent); } diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java index a93c65151..f3b1d587f 100644 --- a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java +++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java @@ -20,6 +20,8 @@ import android.app.job.JobWorkItem; import android.content.Context; import android.net.Uri; import android.support.annotation.MainThread; +import android.support.annotation.VisibleForTesting; +import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.util.Pair; import com.android.dialer.common.Assert; @@ -62,6 +64,7 @@ public abstract class TranscriptionTask implements Runnable { private final JobWorkItem workItem; private final TranscriptionClientFactory clientFactory; private final Uri voicemailUri; + protected final PhoneAccountHandle phoneAccountHandle; private final TranscriptionDbHelper databaseHelper; protected final TranscriptionConfigProvider configProvider; protected ByteString audioData; @@ -86,6 +89,7 @@ public abstract class TranscriptionTask implements Runnable { this.workItem = workItem; this.clientFactory = clientFactory; this.voicemailUri = TranscriptionService.getVoicemailUri(workItem); + this.phoneAccountHandle = TranscriptionService.getPhoneAccountHandle(workItem); this.configProvider = configProvider; databaseHelper = new TranscriptionDbHelper(context, voicemailUri); } @@ -240,14 +244,24 @@ public abstract class TranscriptionTask implements Runnable { return false; } - if (audioData.startsWith(ByteString.copyFromUtf8(AMR_PREFIX))) { - encoding = AudioFormat.AMR_NB_8KHZ; - } else { + encoding = getAudioFormat(audioData); + if (encoding == AudioFormat.AUDIO_FORMAT_UNSPECIFIED) { VvmLog.i(TAG, "Transcriber.readAndValidateAudioFile, unknown encoding"); - encoding = AudioFormat.AUDIO_FORMAT_UNSPECIFIED; return false; } return true; } + + private static AudioFormat getAudioFormat(ByteString audioData) { + return audioData != null && audioData.startsWith(ByteString.copyFromUtf8(AMR_PREFIX)) + ? AudioFormat.AMR_NB_8KHZ + : AudioFormat.AUDIO_FORMAT_UNSPECIFIED; + } + + @VisibleForTesting + void setAudioDataForTesting(ByteString audioData) { + this.audioData = audioData; + encoding = getAudioFormat(audioData); + } } diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java index e75728014..f946607b5 100644 --- a/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java +++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTaskAsync.java @@ -21,11 +21,13 @@ import android.util.Pair; import com.android.dialer.common.Assert; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; +import com.android.voicemail.VoicemailComponent; import com.android.voicemail.impl.VvmLog; import com.android.voicemail.impl.transcribe.TranscriptionService.JobCallback; import com.android.voicemail.impl.transcribe.grpc.GetTranscriptResponseAsync; import com.android.voicemail.impl.transcribe.grpc.TranscriptionClientFactory; import com.android.voicemail.impl.transcribe.grpc.TranscriptionResponseAsync; +import com.google.internal.communications.voicemailtranscription.v1.DonationPreference; import com.google.internal.communications.voicemailtranscription.v1.GetTranscriptRequest; import com.google.internal.communications.voicemailtranscription.v1.TranscribeVoicemailAsyncRequest; import com.google.internal.communications.voicemailtranscription.v1.TranscriptionStatus; @@ -119,13 +121,22 @@ public class TranscriptionTaskAsync extends TranscriptionTask { return new Pair<>(null, TranscriptionStatus.FAILED_NO_RETRY); } - private TranscribeVoicemailAsyncRequest getUploadRequest() { + TranscribeVoicemailAsyncRequest getUploadRequest() { return TranscribeVoicemailAsyncRequest.newBuilder() .setVoicemailData(audioData) .setAudioFormat(encoding) + .setDonationPreference( + isDonationEnabled() ? DonationPreference.DONATE : DonationPreference.DO_NOT_DONATE) .build(); } + private boolean isDonationEnabled() { + return phoneAccountHandle != null + && VoicemailComponent.get(context) + .getVoicemailClient() + .isVoicemailDonationEnabled(context, phoneAccountHandle); + } + private GetTranscriptRequest getGetTranscriptRequest(TranscriptionResponseAsync uploadResponse) { Assert.checkArgument(uploadResponse.getTranscriptionId() != null); return GetTranscriptRequest.newBuilder() diff --git a/java/com/android/voicemail/stub/StubVoicemailClient.java b/java/com/android/voicemail/stub/StubVoicemailClient.java index c2c7a6d38..4b8ed9ab8 100644 --- a/java/com/android/voicemail/stub/StubVoicemailClient.java +++ b/java/com/android/voicemail/stub/StubVoicemailClient.java @@ -75,6 +75,16 @@ public final class StubVoicemailClient implements VoicemailClient { public void setVoicemailArchiveEnabled( Context context, PhoneAccountHandle phoneAccountHandle, boolean value) {} + @Override + public boolean isVoicemailTranscriptionAvailable(Context context) { + return false; + } + + @Override + public boolean isVoicemailDonationEnabled(Context context, PhoneAccountHandle account) { + return false; + } + @Override public Intent getSetPinIntent(Context context, PhoneAccountHandle phoneAccountHandle) { Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL); -- cgit v1.2.3