From 5e7d12ef1effb30f8f3cef918e3f15aec2eb521c Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Fri, 26 Jan 2018 11:21:44 -0800 Subject: Add voice search to NUI. Bug: 72525718 Test: MainActivityIntegrationTest PiperOrigin-RevId: 183418364 Change-Id: I30a4b7fe3e8a82c1b5cddcd747bd01ebd127b624 --- .../com/android/dialer/main/impl/MainActivity.java | 11 +++++++ .../dialer/main/impl/MainSearchController.java | 36 ++++++++++++++++++++-- .../dialer/main/impl/res/values/strings.xml | 3 ++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java index 168589f13..242bf2d48 100644 --- a/java/com/android/dialer/main/impl/MainActivity.java +++ b/java/com/android/dialer/main/impl/MainActivity.java @@ -28,6 +28,7 @@ import android.widget.ImageView; import com.android.dialer.calllog.ui.NewCallLogFragment; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; +import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactsfragment.ContactsFragment; import com.android.dialer.contactsfragment.ContactsFragment.Header; import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener; @@ -116,6 +117,16 @@ public final class MainActivity extends AppCompatActivity searchController.onSaveInstanceState(bundle); } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == ActivityRequestCodes.DIALTACTS_VOICE_SEARCH) { + searchController.onVoiceResults(resultCode, data); + } else { + LogUtil.e("MainActivity.onActivityResult", "Unknown request code: " + requestCode); + } + } + @Override public void onContactSelected(ImageView photo, Uri contactUri, long contactId) { // TODO(calderwoodra): Add impression logging diff --git a/java/com/android/dialer/main/impl/MainSearchController.java b/java/com/android/dialer/main/impl/MainSearchController.java index 041e32ed7..b01f80de6 100644 --- a/java/com/android/dialer/main/impl/MainSearchController.java +++ b/java/com/android/dialer/main/impl/MainSearchController.java @@ -17,16 +17,22 @@ package com.android.dialer.main.impl; import android.app.FragmentTransaction; +import android.content.ActivityNotFoundException; +import android.content.Intent; import android.os.Bundle; +import android.speech.RecognizerIntent; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; +import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; +import android.widget.Toast; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.dialpadview.DialpadFragment; import com.android.dialer.dialpadview.DialpadFragment.DialpadListener; import com.android.dialer.dialpadview.DialpadFragment.OnDialpadQueryChangedListener; @@ -36,6 +42,7 @@ import com.android.dialer.searchfragment.list.NewSearchFragment; import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener; import com.android.dialer.util.ViewUtil; import com.google.common.base.Optional; +import java.util.ArrayList; /** * Search controller for handling all the logic related to entering and exiting the search UI. @@ -255,8 +262,12 @@ final class MainSearchController implements SearchBarListener { */ @Override public void onSearchBarClicked() { + openSearch(Optional.absent()); + } + + private void openSearch(Optional query) { fab.hide(); - toolbar.expand(/* animate=*/ true, Optional.absent()); + toolbar.expand(/* animate=*/ true, query); toolbar.showKeyboard(); hideBottomNav(); @@ -294,7 +305,28 @@ final class MainSearchController implements SearchBarListener { } @Override - public void onVoiceButtonClicked(VoiceSearchResultCallback voiceSearchResultCallback) {} + public void onVoiceButtonClicked(VoiceSearchResultCallback voiceSearchResultCallback) { + try { + Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + mainActivity.startActivityForResult(voiceIntent, ActivityRequestCodes.DIALTACTS_VOICE_SEARCH); + } catch (ActivityNotFoundException e) { + Toast.makeText(mainActivity, R.string.voice_search_not_available, Toast.LENGTH_SHORT).show(); + } + } + + public void onVoiceResults(int resultCode, Intent data) { + if (resultCode == AppCompatActivity.RESULT_OK) { + ArrayList matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); + if (matches.size() > 0) { + LogUtil.i("MainSearchController.onVoiceResults", "voice search - match found"); + openSearch(Optional.of(matches.get(0))); + } else { + LogUtil.i("MainSearchController.onVoiceResults", "voice search - nothing heard"); + } + } else { + LogUtil.e("MainSearchController.onVoiceResults", "voice search failed"); + } + } @Override public void openSettings() {} diff --git a/java/com/android/dialer/main/impl/res/values/strings.xml b/java/com/android/dialer/main/impl/res/values/strings.xml index f530fa2bf..0fc1246d6 100644 --- a/java/com/android/dialer/main/impl/res/values/strings.xml +++ b/java/com/android/dialer/main/impl/res/values/strings.xml @@ -46,4 +46,7 @@ Voicemail Contacts + + + Voice search not available -- cgit v1.2.3 From 33d4d88ae74b755501da31906f9393d4c9f6f344 Mon Sep 17 00:00:00 2001 From: uabdullah Date: Fri, 26 Jan 2018 11:32:07 -0800 Subject: Disable seekbar user seeking By default the seekbar should be disabled unless being played or the voicemails have downloaded. This first part of the seekbar update ensures that a user is not able to seek, and the seekbar will only be updated automatically when the voicemail is being played. Bug: 7252855 Test: N/A PiperOrigin-RevId: 183419966 Change-Id: I4e492279402d76d3e1ece03dded9b402c88138c8 --- .../listui/NewVoicemailMediaPlayerView.java | 12 ++++++++++++ .../listui/res/drawable-hdpi/ic_handle.png | Bin 0 -> 218 bytes .../listui/res/drawable-mdpi/ic_handle.png | Bin 0 -> 160 bytes .../listui/res/drawable-xhdpi/ic_handle.png | Bin 0 -> 285 bytes .../listui/res/drawable-xxhdpi/ic_handle.png | Bin 0 -> 311 bytes .../listui/res/drawable-xxxhdpi/ic_handle.png | Bin 0 -> 467 bytes .../drawable/ic_voicemail_seek_handle_disabled.xml | 20 ++++++++++++++++++++ .../dialer/voicemail/listui/res/values/colors.xml | 19 +++++++++++++++++++ 8 files changed, 51 insertions(+) create mode 100644 java/com/android/dialer/voicemail/listui/res/drawable-hdpi/ic_handle.png create mode 100644 java/com/android/dialer/voicemail/listui/res/drawable-mdpi/ic_handle.png create mode 100644 java/com/android/dialer/voicemail/listui/res/drawable-xhdpi/ic_handle.png create mode 100644 java/com/android/dialer/voicemail/listui/res/drawable-xxhdpi/ic_handle.png create mode 100644 java/com/android/dialer/voicemail/listui/res/drawable-xxxhdpi/ic_handle.png create mode 100644 java/com/android/dialer/voicemail/listui/res/drawable/ic_voicemail_seek_handle_disabled.xml create mode 100644 java/com/android/dialer/voicemail/listui/res/values/colors.xml diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java index 3becd271f..0234f6495 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java @@ -20,6 +20,7 @@ import android.app.FragmentManager; import android.content.Context; import android.content.Intent; import android.database.Cursor; +import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; import android.provider.VoicemailContract; @@ -61,6 +62,8 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { private ImageButton deleteButton; private TextView currentSeekBarPosition; private SeekBar seekBarView; + private Drawable voicemailSeekHandleDisabled; + private TextView totalDurationView; private TextView voicemailLoadingStatusView; private Uri voicemailUri; @@ -96,6 +99,11 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { deleteButton = findViewById(R.id.deleteButton); totalDurationView = findViewById(R.id.playback_seek_total_duration); voicemailLoadingStatusView = findViewById(R.id.playback_state_text); + + voicemailSeekHandleDisabled = + getContext() + .getResources() + .getDrawable(R.drawable.ic_voicemail_seek_handle_disabled, getContext().getTheme()); } private void setupListenersForMediaPlayerButtons() { @@ -167,6 +175,10 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { initializeMediaPlayerButtonsAndViews(); setupListenersForMediaPlayerButtons(); + // TODO(uabdullah): Handle seekbar seeking properly (a bug) + seekBarView.setEnabled(false); + seekBarView.setThumb(voicemailSeekHandleDisabled); + // During the binding we only send a request to the adapter to tell us what the // state of the media player should be and call that function. // This could be the paused state, or the playing state of the resume state. diff --git a/java/com/android/dialer/voicemail/listui/res/drawable-hdpi/ic_handle.png b/java/com/android/dialer/voicemail/listui/res/drawable-hdpi/ic_handle.png new file mode 100644 index 000000000..315a0dd40 Binary files /dev/null and b/java/com/android/dialer/voicemail/listui/res/drawable-hdpi/ic_handle.png differ diff --git a/java/com/android/dialer/voicemail/listui/res/drawable-mdpi/ic_handle.png b/java/com/android/dialer/voicemail/listui/res/drawable-mdpi/ic_handle.png new file mode 100644 index 000000000..8bcec11e0 Binary files /dev/null and b/java/com/android/dialer/voicemail/listui/res/drawable-mdpi/ic_handle.png differ diff --git a/java/com/android/dialer/voicemail/listui/res/drawable-xhdpi/ic_handle.png b/java/com/android/dialer/voicemail/listui/res/drawable-xhdpi/ic_handle.png new file mode 100644 index 000000000..36f3466a6 Binary files /dev/null and b/java/com/android/dialer/voicemail/listui/res/drawable-xhdpi/ic_handle.png differ diff --git a/java/com/android/dialer/voicemail/listui/res/drawable-xxhdpi/ic_handle.png b/java/com/android/dialer/voicemail/listui/res/drawable-xxhdpi/ic_handle.png new file mode 100644 index 000000000..9a1651cee Binary files /dev/null and b/java/com/android/dialer/voicemail/listui/res/drawable-xxhdpi/ic_handle.png differ diff --git a/java/com/android/dialer/voicemail/listui/res/drawable-xxxhdpi/ic_handle.png b/java/com/android/dialer/voicemail/listui/res/drawable-xxxhdpi/ic_handle.png new file mode 100644 index 000000000..c6dbf3875 Binary files /dev/null and b/java/com/android/dialer/voicemail/listui/res/drawable-xxxhdpi/ic_handle.png differ diff --git a/java/com/android/dialer/voicemail/listui/res/drawable/ic_voicemail_seek_handle_disabled.xml b/java/com/android/dialer/voicemail/listui/res/drawable/ic_voicemail_seek_handle_disabled.xml new file mode 100644 index 000000000..5e974c45a --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/res/drawable/ic_voicemail_seek_handle_disabled.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/java/com/android/dialer/voicemail/listui/res/values/colors.xml b/java/com/android/dialer/voicemail/listui/res/values/colors.xml new file mode 100644 index 000000000..6ecf4c229 --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/res/values/colors.xml @@ -0,0 +1,19 @@ + + + + #80000000 + \ No newline at end of file -- cgit v1.2.3 From 97d0b5e504a52a83e87f7dc7eec571a44b846b33 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Fri, 26 Jan 2018 12:11:26 -0800 Subject: Pressing dial with an empty dialpad now queries the last number in NUI. Bug: 72526019 Test: manual PiperOrigin-RevId: 183425741 Change-Id: Ied1b369d00baefe02db04ade26bee9faac4f829c --- java/com/android/dialer/app/DialtactsActivity.java | 12 ++- .../android/dialer/app/calllog/CallLogAsync.java | 96 ---------------------- .../com/android/dialer/main/impl/MainActivity.java | 10 ++- 3 files changed, 17 insertions(+), 101 deletions(-) delete mode 100644 java/com/android/dialer/app/calllog/CallLogAsync.java diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java index 7592c6669..4b0384ea5 100644 --- a/java/com/android/dialer/app/DialtactsActivity.java +++ b/java/com/android/dialer/app/DialtactsActivity.java @@ -73,7 +73,6 @@ import com.android.dialer.animation.AnimUtils; import com.android.dialer.animation.AnimationListenerAdapter; import com.android.dialer.app.calllog.CallLogActivity; import com.android.dialer.app.calllog.CallLogAdapter; -import com.android.dialer.app.calllog.CallLogAsync; import com.android.dialer.app.calllog.CallLogFragment; import com.android.dialer.app.calllog.CallLogNotificationsService; import com.android.dialer.app.calllog.IntentProvider; @@ -99,6 +98,7 @@ import com.android.dialer.callintent.CallSpecificAppData; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.UiUtil; +import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.compat.CompatUtils; import com.android.dialer.configprovider.ConfigProviderBindings; @@ -912,9 +912,13 @@ public class DialtactsActivity extends TransactionSafeActivity @Override public void getLastOutgoingCall(LastOutgoingCallCallback callback) { - new CallLogAsync() - .getLastOutgoingCall( - new CallLogAsync.GetLastOutgoingCallArgs(this, callback::lastOutgoingCall)); + DialerExecutorComponent.get(this) + .dialerExecutorFactory() + .createUiTaskBuilder( + getFragmentManager(), "Query last phone number", Calls::getLastOutgoingCall) + .onSuccess(output -> callback.lastOutgoingCall(output)) + .build() + .executeParallel(this); } /** Callback from child DialpadFragment when the dialpad is shown. */ diff --git a/java/com/android/dialer/app/calllog/CallLogAsync.java b/java/com/android/dialer/app/calllog/CallLogAsync.java deleted file mode 100644 index 26435f311..000000000 --- a/java/com/android/dialer/app/calllog/CallLogAsync.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2010 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.app.calllog; - -import android.content.Context; -import android.os.AsyncTask; -import android.provider.CallLog.Calls; -import com.android.dialer.common.Assert; - -/** - * Class to access the call log asynchronously to avoid carrying out database operations on the UI - * thread, using an {@link AsyncTask}. - * - *
 Typical usage: ==============
- *
- * // From an activity... String mLastNumber = "";
- *
- * CallLogAsync log = new CallLogAsync();
- *
- * CallLogAsync.GetLastOutgoingCallArgs lastCallArgs = new CallLogAsync.GetLastOutgoingCallArgs(
- * this, new CallLogAsync.OnLastOutgoingCallComplete() { public void lastOutgoingCall(String number)
- * { mLastNumber = number; } }); log.getLastOutgoingCall(lastCallArgs); 
- */ -public class CallLogAsync { - - /** CallLog.getLastOutgoingCall(...) */ - public AsyncTask getLastOutgoingCall(GetLastOutgoingCallArgs args) { - Assert.isMainThread(); - return new GetLastOutgoingCallTask(args.callback).execute(args); - } - - /** Interface to retrieve the last dialed number asynchronously. */ - public interface OnLastOutgoingCallComplete { - - /** @param number The last dialed number or an empty string if none exists yet. */ - void lastOutgoingCall(String number); - } - - /** Parameter object to hold the args to get the last outgoing call from the call log DB. */ - public static class GetLastOutgoingCallArgs { - - public final Context context; - public final OnLastOutgoingCallComplete callback; - - public GetLastOutgoingCallArgs(Context context, OnLastOutgoingCallComplete callback) { - this.context = context; - this.callback = callback; - } - } - - /** AsyncTask to get the last outgoing call from the DB. */ - private class GetLastOutgoingCallTask extends AsyncTask { - - private final OnLastOutgoingCallComplete callback; - - public GetLastOutgoingCallTask(OnLastOutgoingCallComplete callback) { - this.callback = callback; - } - - // Happens on a background thread. We cannot run the callback - // here because only the UI thread can modify the view - // hierarchy (e.g enable/disable the dial button). The - // callback is ran rom the post execute method. - @Override - protected String doInBackground(GetLastOutgoingCallArgs... list) { - String number = ""; - for (GetLastOutgoingCallArgs args : list) { - // May block. Select only the last one. - number = Calls.getLastOutgoingCall(args.context); - } - return number; // passed to the onPostExecute method. - } - - // Happens on the UI thread, it is safe to run the callback - // that may do some work on the views. - @Override - protected void onPostExecute(String number) { - Assert.isMainThread(); - callback.lastOutgoingCall(number); - } - } -} diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java index 242bf2d48..3edf6c6af 100644 --- a/java/com/android/dialer/main/impl/MainActivity.java +++ b/java/com/android/dialer/main/impl/MainActivity.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.provider.CallLog.Calls; import android.provider.ContactsContract.QuickContact; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.FragmentTransaction; @@ -27,6 +28,7 @@ import android.support.v7.app.AppCompatActivity; import android.widget.ImageView; import com.android.dialer.calllog.ui.NewCallLogFragment; import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.compat.CompatUtils; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.contactsfragment.ContactsFragment; @@ -141,7 +143,13 @@ public final class MainActivity extends AppCompatActivity @Override // DialpadListener public void getLastOutgoingCall(LastOutgoingCallCallback callback) { - // TODO(calderwoodra): migrate CallLogAsync class outside of dialer/app and call it here. + DialerExecutorComponent.get(this) + .dialerExecutorFactory() + .createUiTaskBuilder( + getFragmentManager(), "Query last phone number", Calls::getLastOutgoingCall) + .onSuccess(output -> callback.lastOutgoingCall(output)) + .build() + .executeParallel(this); } @Override // DialpadListener -- cgit v1.2.3 From 351cbcf3aed969db9b03fbcfc941cf3e086b0720 Mon Sep 17 00:00:00 2001 From: uabdullah Date: Fri, 26 Jan 2018 12:36:01 -0800 Subject: Disable phone icon for unknown numbers in NUI Voicemail The phone icon should be disabled for unknown numbers in the NUI Voicemail, so that those numbers may not be called. This should have the same logic as as what we do for the call log. Bug: 72449247 Test: Unit Test PiperOrigin-RevId: 183428831 Change-Id: If1ecc3b4d47de04bccf69ae735a619f6b33c3bbd --- .../listui/NewVoicemailMediaPlayerView.java | 27 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java index 0234f6495..dd59712a4 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java @@ -150,7 +150,9 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { Assert.isNotNull(voicemailEntryFromAdapter); Uri uri = Uri.parse(voicemailEntryFromAdapter.voicemailUri()); + numberVoicemailFrom = voicemailEntryFromAdapter.number().getRawInput().getNumber(); + Assert.isNotNull(viewHolder); Assert.isNotNull(uri); Assert.isNotNull(listener); @@ -179,6 +181,8 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { seekBarView.setEnabled(false); seekBarView.setThumb(voicemailSeekHandleDisabled); + updatePhoneIcon(numberVoicemailFrom); + // During the binding we only send a request to the adapter to tell us what the // state of the media player should be and call that function. // This could be the paused state, or the playing state of the resume state. @@ -231,6 +235,23 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { } } + /** + * Updates the phone icon depending if we can dial it or not. + * + *

Note: This must be called after the onClickListeners have been set, otherwise isClickable() + * state is not maintained. + */ + private void updatePhoneIcon(@Nullable String numberVoicemailFrom) { + // TODO(uabdullah): Handle restricted/blocked numbers (a bug) + if (TextUtils.isEmpty(numberVoicemailFrom)) { + phoneButton.setEnabled(false); + phoneButton.setClickable(false); + } else { + phoneButton.setEnabled(true); + phoneButton.setClickable(true); + } + } + private final OnSeekBarChangeListener seekbarChangeListener = new OnSeekBarChangeListener() { @Override @@ -478,11 +499,11 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { audioManager.setMode(AudioManager.STREAM_MUSIC); if (audioManager.isSpeakerphoneOn()) { LogUtil.i( - "NewVoicemailMediaPlayer.phoneButtonListener", "speaker was on, turning it off"); + "NewVoicemailMediaPlayer.speakerButtonListener", "speaker was on, turning it off"); audioManager.setSpeakerphoneOn(false); } else { LogUtil.i( - "NewVoicemailMediaPlayer.phoneButtonListener", "speaker was off, turning it on"); + "NewVoicemailMediaPlayer.speakerButtonListener", "speaker was off, turning it on"); audioManager.setSpeakerphoneOn(true); } // TODO(uabdullah): Handle colors of speaker icon when speaker is on and off. @@ -490,8 +511,6 @@ public final class NewVoicemailMediaPlayerView extends LinearLayout { }; // TODO(uabdullah): Add phone account handle (a bug) - // TODO(uabdullah): If the call cannot be made then the phone icon should be greyed out - // (a bug) private final View.OnClickListener phoneButtonListener = new View.OnClickListener() { @Override -- cgit v1.2.3