diff options
author | Eric Erfanian <erfanian@google.com> | 2017-02-22 16:32:36 -0800 |
---|---|---|
committer | Eric Erfanian <erfanian@google.com> | 2017-03-01 09:56:52 -0800 |
commit | ccca31529c07970e89419fb85a9e8153a5396838 (patch) | |
tree | a7034c0a01672b97728c13282a2672771cd28baa /src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java | |
parent | e7ae4624ba6f25cb8e648db74e0d64c0113a16ba (diff) |
Update dialer sources.
Test: Built package and system image.
This change clobbers the old source, and is an export
from an internal Google repository.
The internal repository was forked form Android in March,
and this change includes modifications since then, to
near the v8 release.
Since the fork, we've moved code from monolithic to independent modules. In addition,
we've switched to Blaze/Bazel as the build sysetm. This export, however, still uses make.
New dependencies have been added:
- Dagger
- Auto-Value
- Glide
- Libshortcutbadger
Going forward, development will still be in Google3, and the Gerrit release
will become an automated export, with the next drop happening in ~ two weeks.
Android.mk includes local modifications from ToT.
Abridged changelog:
Bug fixes
● Not able to mute, add a call when using Phone app in multiwindow mode
● Double tap on keypad triggering multiple key and tones
● Reported spam numbers not showing as spam in the call log
● Crash when user tries to block number while Phone app is not set as default
● Crash when user picks a number from search auto-complete list
Visual Voicemail (VVM) improvements
● Share Voicemail audio via standard exporting mechanisms that support file attachment
(email, MMS, etc.)
● Make phone number, email and web sites in VVM transcript clickable
● Set PIN before declining VVM Terms of Service {Carrier}
● Set client type for outbound visual voicemail SMS {Carrier}
New incoming call and incall UI on older devices
(Android M)
● Updated Phone app icon
● New incall UI (large buttons, button labels)
● New and animated Answer/Reject gestures
Accessibility
● Add custom answer/decline call buttons on answer screen for touch exploration
accessibility services
● Increase size of touch target
● Add verbal feedback when a Voicemail fails to load
● Fix pressing of Phone buttons while in a phone call using Switch Access
● Fix selecting and opening contacts in talkback mode
● Split focus for ‘Learn More’ link in caller id & spam to help distinguish similar text
Other
● Backup & Restore for App Preferences
● Prompt user to enable Wi-Fi calling if the call ends due to out of service and Wi-Fi is
connected
● Rename “Dialpad” to “Keypad”
● Show "Private number" for restricted calls
● Delete unused items (vcard, add contact, call history) from Phone menu
Change-Id: I2a7e53532a24c21bf308bf0a6d178d7ddbca4958
Diffstat (limited to 'src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java')
-rw-r--r-- | src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java | 638 |
1 files changed, 0 insertions, 638 deletions
diff --git a/src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java b/src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java deleted file mode 100644 index 7d6fe78d1..000000000 --- a/src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Copyright (C) 2011 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.voicemail; - -import android.content.ContentUris; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.util.AttributeSet; -import android.support.design.widget.Snackbar; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.Space; -import android.widget.TextView; -import android.widget.Toast; - -import com.android.common.io.MoreCloseables; -import com.android.dialer.PhoneCallDetails; -import com.android.dialer.R; -import com.android.dialer.calllog.CallLogAsyncTaskUtil; - -import com.android.dialer.database.VoicemailArchiveContract; -import com.android.dialer.database.VoicemailArchiveContract.VoicemailArchive; -import com.android.dialer.util.AsyncTaskExecutor; -import com.android.dialer.util.AsyncTaskExecutors; -import com.android.dialerbind.ObjectFactory; -import com.google.common.annotations.VisibleForTesting; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledExecutorService; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.NotThreadSafe; -import javax.annotation.concurrent.ThreadSafe; - -/** - * Displays and plays a single voicemail. See {@link VoicemailPlaybackPresenter} for - * details on the voicemail playback implementation. - * - * This class is not thread-safe, it is thread-confined. All calls to all public - * methods on this class are expected to come from the main ui thread. - */ -@NotThreadSafe -public class VoicemailPlaybackLayout extends LinearLayout - implements VoicemailPlaybackPresenter.PlaybackView, - CallLogAsyncTaskUtil.CallLogAsyncTaskListener { - private static final String TAG = VoicemailPlaybackLayout.class.getSimpleName(); - private static final int VOICEMAIL_DELETE_DELAY_MS = 3000; - private static final int VOICEMAIL_ARCHIVE_DELAY_MS = 3000; - - /** The enumeration of {@link AsyncTask} objects we use in this class. */ - public enum Tasks { - QUERY_ARCHIVED_STATUS - } - - /** - * Controls the animation of the playback slider. - */ - @ThreadSafe - private final class PositionUpdater implements Runnable { - - /** Update rate for the slider, 30fps. */ - private static final int SLIDER_UPDATE_PERIOD_MILLIS = 1000 / 30; - - private int mDurationMs; - private final ScheduledExecutorService mExecutorService; - private final Object mLock = new Object(); - @GuardedBy("mLock") private ScheduledFuture<?> mScheduledFuture; - - private Runnable mUpdateClipPositionRunnable = new Runnable() { - @Override - public void run() { - int currentPositionMs = 0; - synchronized (mLock) { - if (mScheduledFuture == null || mPresenter == null) { - // This task has been canceled. Just stop now. - return; - } - currentPositionMs = mPresenter.getMediaPlayerPosition(); - } - setClipPosition(currentPositionMs, mDurationMs); - } - }; - - public PositionUpdater(int durationMs, ScheduledExecutorService executorService) { - mDurationMs = durationMs; - mExecutorService = executorService; - } - - @Override - public void run() { - post(mUpdateClipPositionRunnable); - } - - public void startUpdating() { - synchronized (mLock) { - cancelPendingRunnables(); - mScheduledFuture = mExecutorService.scheduleAtFixedRate( - this, 0, SLIDER_UPDATE_PERIOD_MILLIS, TimeUnit.MILLISECONDS); - } - } - - public void stopUpdating() { - synchronized (mLock) { - cancelPendingRunnables(); - } - } - - @GuardedBy("mLock") - private void cancelPendingRunnables() { - if (mScheduledFuture != null) { - mScheduledFuture.cancel(true); - mScheduledFuture = null; - } - removeCallbacks(mUpdateClipPositionRunnable); - } - } - - /** - * Handle state changes when the user manipulates the seek bar. - */ - private final OnSeekBarChangeListener mSeekBarChangeListener = new OnSeekBarChangeListener() { - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - if (mPresenter != null) { - mPresenter.pausePlaybackForSeeking(); - } - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - if (mPresenter != null) { - mPresenter.resumePlaybackAfterSeeking(seekBar.getProgress()); - } - } - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - setClipPosition(progress, seekBar.getMax()); - // Update the seek position if user manually changed it. This makes sure position gets - // updated when user use volume button to seek playback in talkback mode. - if (fromUser) { - mPresenter.seek(progress); - } - } - }; - - /** - * Click listener to toggle speakerphone. - */ - private final View.OnClickListener mSpeakerphoneListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mPresenter != null) { - mPresenter.toggleSpeakerphone(); - } - } - }; - - /** - * Click listener to play or pause voicemail playback. - */ - private final View.OnClickListener mStartStopButtonListener = new View.OnClickListener() { - @Override - public void onClick(View view) { - if (mPresenter == null) { - return; - } - - if (mIsPlaying) { - mPresenter.pausePlayback(); - } else { - mPresenter.resumePlayback(); - } - } - }; - - private final View.OnClickListener mDeleteButtonListener = new View.OnClickListener() { - @Override - public void onClick(View view ) { - if (mPresenter == null) { - return; - } - mPresenter.pausePlayback(); - mPresenter.onVoicemailDeleted(); - - final Uri deleteUri = mVoicemailUri; - final Runnable deleteCallback = new Runnable() { - @Override - public void run() { - if (Objects.equals(deleteUri, mVoicemailUri)) { - CallLogAsyncTaskUtil.deleteVoicemail(mContext, deleteUri, - VoicemailPlaybackLayout.this); - } - } - }; - - final Handler handler = new Handler(); - // Add a little buffer time in case the user clicked "undo" at the end of the delay - // window. - handler.postDelayed(deleteCallback, VOICEMAIL_DELETE_DELAY_MS + 50); - - Snackbar.make(VoicemailPlaybackLayout.this, R.string.snackbar_voicemail_deleted, - Snackbar.LENGTH_LONG) - .setDuration(VOICEMAIL_DELETE_DELAY_MS) - .setAction(R.string.snackbar_voicemail_deleted_undo, - new View.OnClickListener() { - @Override - public void onClick(View view) { - mPresenter.onVoicemailDeleteUndo(); - handler.removeCallbacks(deleteCallback); - } - }) - .setActionTextColor( - mContext.getResources().getColor( - R.color.dialer_snackbar_action_text_color)) - .show(); - } - }; - - private final View.OnClickListener mArchiveButtonListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mPresenter == null || isArchiving(mVoicemailUri)) { - return; - } - mIsArchiving.add(mVoicemailUri); - mPresenter.pausePlayback(); - updateArchiveUI(mVoicemailUri); - disableUiElements(); - mPresenter.archiveContent(mVoicemailUri, true); - } - }; - - private final View.OnClickListener mShareButtonListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mPresenter == null || isArchiving(mVoicemailUri)) { - return; - } - disableUiElements(); - mPresenter.archiveContent(mVoicemailUri, false); - } - }; - - private Context mContext; - private VoicemailPlaybackPresenter mPresenter; - private Uri mVoicemailUri; - private final AsyncTaskExecutor mAsyncTaskExecutor = - AsyncTaskExecutors.createAsyncTaskExecutor(); - private boolean mIsPlaying = false; - /** - * Keeps track of which voicemails are currently being archived in order to update the voicemail - * card UI every time a user opens a new card. - */ - private static final ArrayList<Uri> mIsArchiving = new ArrayList<>(); - - private SeekBar mPlaybackSeek; - private ImageButton mStartStopButton; - private ImageButton mPlaybackSpeakerphone; - private ImageButton mDeleteButton; - private ImageButton mArchiveButton; - private ImageButton mShareButton; - - private Space mArchiveSpace; - private Space mShareSpace; - - private TextView mStateText; - private TextView mPositionText; - private TextView mTotalDurationText; - - private PositionUpdater mPositionUpdater; - private Drawable mVoicemailSeekHandleEnabled; - private Drawable mVoicemailSeekHandleDisabled; - - public VoicemailPlaybackLayout(Context context) { - this(context, null); - } - - public VoicemailPlaybackLayout(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - LayoutInflater inflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.voicemail_playback_layout, this); - } - - @Override - public void setPresenter(VoicemailPlaybackPresenter presenter, Uri voicemailUri) { - mPresenter = presenter; - mVoicemailUri = voicemailUri; - if (ObjectFactory.isVoicemailArchiveEnabled(mContext)) { - updateArchiveUI(mVoicemailUri); - updateArchiveButton(mVoicemailUri); - } - - if (ObjectFactory.isVoicemailShareEnabled(mContext)) { - // Show share button and space before it - mShareSpace.setVisibility(View.VISIBLE); - mShareButton.setVisibility(View.VISIBLE); - } - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - mPlaybackSeek = (SeekBar) findViewById(R.id.playback_seek); - mStartStopButton = (ImageButton) findViewById(R.id.playback_start_stop); - mPlaybackSpeakerphone = (ImageButton) findViewById(R.id.playback_speakerphone); - mDeleteButton = (ImageButton) findViewById(R.id.delete_voicemail); - mArchiveButton =(ImageButton) findViewById(R.id.archive_voicemail); - mShareButton = (ImageButton) findViewById(R.id.share_voicemail); - - mArchiveSpace = (Space) findViewById(R.id.space_before_archive_voicemail); - mShareSpace = (Space) findViewById(R.id.space_before_share_voicemail); - - mStateText = (TextView) findViewById(R.id.playback_state_text); - mPositionText = (TextView) findViewById(R.id.playback_position_text); - mTotalDurationText = (TextView) findViewById(R.id.total_duration_text); - - mPlaybackSeek.setOnSeekBarChangeListener(mSeekBarChangeListener); - mStartStopButton.setOnClickListener(mStartStopButtonListener); - mPlaybackSpeakerphone.setOnClickListener(mSpeakerphoneListener); - mDeleteButton.setOnClickListener(mDeleteButtonListener); - mArchiveButton.setOnClickListener(mArchiveButtonListener); - mShareButton.setOnClickListener(mShareButtonListener); - - mPositionText.setText(formatAsMinutesAndSeconds(0)); - mTotalDurationText.setText(formatAsMinutesAndSeconds(0)); - - mVoicemailSeekHandleEnabled = getResources().getDrawable( - R.drawable.ic_voicemail_seek_handle, mContext.getTheme()); - mVoicemailSeekHandleDisabled = getResources().getDrawable( - R.drawable.ic_voicemail_seek_handle_disabled, mContext.getTheme()); - } - - @Override - public void onPlaybackStarted(int duration, ScheduledExecutorService executorService) { - mIsPlaying = true; - - mStartStopButton.setImageResource(R.drawable.ic_pause); - - if (mPositionUpdater != null) { - mPositionUpdater.stopUpdating(); - mPositionUpdater = null; - } - mPositionUpdater = new PositionUpdater(duration, executorService); - mPositionUpdater.startUpdating(); - } - - @Override - public void onPlaybackStopped() { - mIsPlaying = false; - - mStartStopButton.setImageResource(R.drawable.ic_play_arrow); - - if (mPositionUpdater != null) { - mPositionUpdater.stopUpdating(); - mPositionUpdater = null; - } - } - - @Override - public void onPlaybackError() { - if (mPositionUpdater != null) { - mPositionUpdater.stopUpdating(); - } - - disableUiElements(); - mStateText.setText(getString(R.string.voicemail_playback_error)); - } - - @Override - public void onSpeakerphoneOn(boolean on) { - if (on) { - mPlaybackSpeakerphone.setImageResource(R.drawable.ic_volume_up_24dp); - // Speaker is now on, tapping button will turn it off. - mPlaybackSpeakerphone.setContentDescription( - mContext.getString(R.string.voicemail_speaker_off)); - } else { - mPlaybackSpeakerphone.setImageResource(R.drawable.ic_volume_down_24dp); - // Speaker is now off, tapping button will turn it on. - mPlaybackSpeakerphone.setContentDescription( - mContext.getString(R.string.voicemail_speaker_on)); - } - } - - @Override - public void setClipPosition(int positionMs, int durationMs) { - int seekBarPositionMs = Math.max(0, positionMs); - int seekBarMax = Math.max(seekBarPositionMs, durationMs); - if (mPlaybackSeek.getMax() != seekBarMax) { - mPlaybackSeek.setMax(seekBarMax); - } - - mPlaybackSeek.setProgress(seekBarPositionMs); - - mPositionText.setText(formatAsMinutesAndSeconds(seekBarPositionMs)); - mTotalDurationText.setText(formatAsMinutesAndSeconds(durationMs)); - } - - @Override - public void setSuccess() { - mStateText.setText(null); - } - - @Override - public void setIsFetchingContent() { - disableUiElements(); - mStateText.setText(getString(R.string.voicemail_fetching_content)); - } - - @Override - public void setFetchContentTimeout() { - mStartStopButton.setEnabled(true); - mStateText.setText(getString(R.string.voicemail_fetching_timout)); - } - - @Override - public int getDesiredClipPosition() { - return mPlaybackSeek.getProgress(); - } - - @Override - public void disableUiElements() { - mStartStopButton.setEnabled(false); - resetSeekBar(); - } - - @Override - public void enableUiElements() { - mDeleteButton.setEnabled(true); - mStartStopButton.setEnabled(true); - mPlaybackSeek.setEnabled(true); - mPlaybackSeek.setThumb(mVoicemailSeekHandleEnabled); - } - - @Override - public void resetSeekBar() { - mPlaybackSeek.setProgress(0); - mPlaybackSeek.setEnabled(false); - mPlaybackSeek.setThumb(mVoicemailSeekHandleDisabled); - } - - @Override - public void onDeleteCall() {} - - @Override - public void onDeleteVoicemail() { - mPresenter.onVoicemailDeletedInDatabase(); - } - - @Override - public void onGetCallDetails(PhoneCallDetails[] details) {} - - private String getString(int resId) { - return mContext.getString(resId); - } - - /** - * Formats a number of milliseconds as something that looks like {@code 00:05}. - * <p> - * We always use four digits, two for minutes two for seconds. In the very unlikely event - * that the voicemail duration exceeds 99 minutes, the display is capped at 99 minutes. - */ - private String formatAsMinutesAndSeconds(int millis) { - int seconds = millis / 1000; - int minutes = seconds / 60; - seconds -= minutes * 60; - if (minutes > 99) { - minutes = 99; - } - return String.format("%02d:%02d", minutes, seconds); - } - - /** - * Called when a voicemail archive succeeded. If the expanded voicemail was being - * archived, update the card UI. Either way, display a snackbar linking user to archive. - */ - @Override - public void onVoicemailArchiveSucceded(Uri voicemailUri) { - if (isArchiving(voicemailUri)) { - mIsArchiving.remove(voicemailUri); - if (Objects.equals(voicemailUri, mVoicemailUri)) { - onVoicemailArchiveResult(); - hideArchiveButton(); - } - } - - Snackbar.make(this, R.string.snackbar_voicemail_archived, - Snackbar.LENGTH_LONG) - .setDuration(VOICEMAIL_ARCHIVE_DELAY_MS) - .setAction(R.string.snackbar_voicemail_archived_goto, - new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(mContext, - VoicemailArchiveActivity.class); - mContext.startActivity(intent); - } - }) - .setActionTextColor( - mContext.getResources().getColor(R.color.dialer_snackbar_action_text_color)) - .show(); - } - - /** - * If a voicemail archive failed, and the expanded card was being archived, update the card UI. - * Either way, display a toast saying the voicemail archive failed. - */ - @Override - public void onVoicemailArchiveFailed(Uri voicemailUri) { - if (isArchiving(voicemailUri)) { - mIsArchiving.remove(voicemailUri); - if (Objects.equals(voicemailUri, mVoicemailUri)) { - onVoicemailArchiveResult(); - } - } - String toastStr = mContext.getString(R.string.voicemail_archive_failed); - Toast.makeText(mContext, toastStr, Toast.LENGTH_SHORT).show(); - } - - public void hideArchiveButton() { - mArchiveSpace.setVisibility(View.GONE); - mArchiveButton.setVisibility(View.GONE); - mArchiveButton.setClickable(false); - mArchiveButton.setEnabled(false); - } - - /** - * Whenever a voicemail archive succeeds or fails, clear the text displayed in the voicemail - * card. - */ - private void onVoicemailArchiveResult() { - enableUiElements(); - mStateText.setText(null); - mArchiveButton.setColorFilter(null); - } - - /** - * Whether or not the voicemail with the given uri is being archived. - */ - private boolean isArchiving(@Nullable Uri uri) { - return uri != null && mIsArchiving.contains(uri); - } - - /** - * Show the proper text and hide the archive button if the voicemail is still being archived. - */ - private void updateArchiveUI(@Nullable Uri voicemailUri) { - if (!Objects.equals(voicemailUri, mVoicemailUri)) { - return; - } - if (isArchiving(voicemailUri)) { - // If expanded card was in the middle of archiving, disable buttons and display message - disableUiElements(); - mDeleteButton.setEnabled(false); - mArchiveButton.setColorFilter(getResources().getColor(R.color.setting_disabled_color)); - mStateText.setText(getString(R.string.voicemail_archiving_content)); - } else { - onVoicemailArchiveResult(); - } - } - - /** - * Hides the archive button if the voicemail has already been archived, shows otherwise. - * @param voicemailUri the URI of the voicemail for which the archive button needs to be updated - */ - private void updateArchiveButton(@Nullable final Uri voicemailUri) { - if (voicemailUri == null || - !Objects.equals(voicemailUri, mVoicemailUri) || isArchiving(voicemailUri) || - Objects.equals(voicemailUri.getAuthority(),VoicemailArchiveContract.AUTHORITY)) { - return; - } - mAsyncTaskExecutor.submit(Tasks.QUERY_ARCHIVED_STATUS, - new AsyncTask<Void, Void, Boolean>() { - @Override - public Boolean doInBackground(Void... params) { - Cursor cursor = mContext.getContentResolver().query(VoicemailArchive.CONTENT_URI, - null, VoicemailArchive.SERVER_ID + "=" + ContentUris.parseId(mVoicemailUri) - + " AND " + VoicemailArchive.ARCHIVED + "= 1", null, null); - boolean archived = cursor != null && cursor.getCount() > 0; - cursor.close(); - return archived; - } - - @Override - public void onPostExecute(Boolean archived) { - if (!Objects.equals(voicemailUri, mVoicemailUri)) { - return; - } - - if (archived) { - hideArchiveButton(); - } else { - mArchiveSpace.setVisibility(View.VISIBLE); - mArchiveButton.setVisibility(View.VISIBLE); - mArchiveButton.setClickable(true); - mArchiveButton.setEnabled(true); - } - - } - }); - } - - @VisibleForTesting - public String getStateText() { - return mStateText.getText().toString(); - } -} |