1b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson/* 2b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * Copyright (C) 2011 The Android Open Source Project 3b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * 4b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * Licensed under the Apache License, Version 2.0 (the "License"); 5b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * you may not use this file except in compliance with the License. 6b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * You may obtain a copy of the License at 7b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * 8b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * http://www.apache.org/licenses/LICENSE-2.0 9b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * 10b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * Unless required by applicable law or agreed to in writing, software 11b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * distributed under the License is distributed on an "AS IS" BASIS, 12b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * See the License for the specific language governing permissions and 14b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * limitations under the License. 15b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson */ 16b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 17b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonpackage com.android.contacts.voicemail; 18b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 19a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudsonimport static com.android.contacts.CallDetailActivity.EXTRA_VOICEMAIL_START_PLAYBACK; 20a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudsonimport static com.android.contacts.CallDetailActivity.EXTRA_VOICEMAIL_URI; 21a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudson 226faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudsonimport android.app.Activity; 23b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.app.Fragment; 246faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudsonimport android.content.ContentResolver; 25b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.content.Context; 266faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudsonimport android.content.Intent; 276faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudsonimport android.database.ContentObserver; 286faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudsonimport android.database.Cursor; 29b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.media.AudioManager; 30b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.net.Uri; 31b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.os.Bundle; 32fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerdaimport android.os.PowerManager; 336faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudsonimport android.provider.VoicemailContract; 34757aa55194ba962c71feabe99d47b3021c3f294bHugo Hudsonimport android.util.Log; 35b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.view.LayoutInflater; 36b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.view.View; 37b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.view.ViewGroup; 38b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.widget.ImageButton; 39b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.widget.SeekBar; 40b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport android.widget.TextView; 41b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 42e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.common.io.MoreCloseables; 43e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.ProximitySensorAware; 44e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R; 45e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.AsyncTaskExecutors; 46e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.ex.variablespeed.MediaPlayerProxy; 47e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.ex.variablespeed.VariableSpeed; 48e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.base.Preconditions; 49e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng 50b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport java.util.concurrent.ExecutorService; 51b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport java.util.concurrent.Executors; 52b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport java.util.concurrent.ScheduledExecutorService; 53d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudsonimport java.util.concurrent.TimeUnit; 54b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 55d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudsonimport javax.annotation.concurrent.GuardedBy; 56b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonimport javax.annotation.concurrent.NotThreadSafe; 57b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 58b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson/** 59b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * Displays and plays back a single voicemail. 60b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * <p> 61b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * When the Activity containing this Fragment is created, voicemail playback 62b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * will begin immediately. The Activity is expected to be started via an intent 63b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * containing a suitable voicemail uri to playback. 64b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * <p> 65b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * This class is not thread-safe, it is thread-confined. All calls to all public 66b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * methods on this class are expected to come from the main ui thread. 67b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson */ 68b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson@NotThreadSafe 69b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudsonpublic class VoicemailPlaybackFragment extends Fragment { 70757aa55194ba962c71feabe99d47b3021c3f294bHugo Hudson private static final String TAG = "VoicemailPlayback"; 71b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson private static final int NUMBER_OF_THREADS_IN_POOL = 2; 726faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private static final String[] HAS_CONTENT_PROJECTION = new String[] { 736faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson VoicemailContract.Voicemails.HAS_CONTENT, 746faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson }; 75b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 76b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson private VoicemailPlaybackPresenter mPresenter; 77b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson private ScheduledExecutorService mScheduledExecutorService; 786faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private View mPlaybackLayout; 79b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 80b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 81b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public View onCreateView(LayoutInflater inflater, ViewGroup container, 82b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson Bundle savedInstanceState) { 836faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPlaybackLayout = inflater.inflate(R.layout.playback_layout, null); 846faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return mPlaybackLayout; 85b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 86b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 87b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 88b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void onActivityCreated(Bundle savedInstanceState) { 89b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson super.onActivityCreated(savedInstanceState); 90b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mScheduledExecutorService = createScheduledExecutorService(); 91a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudson Bundle arguments = getArguments(); 92a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudson Preconditions.checkNotNull(arguments, "fragment must be started with arguments"); 93a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudson Uri voicemailUri = arguments.getParcelable(EXTRA_VOICEMAIL_URI); 94a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudson Preconditions.checkNotNull(voicemailUri, "fragment must contain EXTRA_VOICEMAIL_URI"); 95a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudson boolean startPlayback = arguments.getBoolean(EXTRA_VOICEMAIL_START_PLAYBACK, false); 96fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda PowerManager powerManager = 97fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); 98fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda PowerManager.WakeLock wakeLock = 99fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda powerManager.newWakeLock( 100fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda PowerManager.SCREEN_DIM_WAKE_LOCK, getClass().getSimpleName()); 1016faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPresenter = new VoicemailPlaybackPresenter(createPlaybackViewImpl(), 102a9ad6945588d3f81968f2462c78fcf1d36874b99Hugo Hudson createMediaPlayer(mScheduledExecutorService), voicemailUri, 1039c747ac625d212a10176082fba6b087035f5d144Hugo Hudson mScheduledExecutorService, startPlayback, 104fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda AsyncTaskExecutors.createAsyncTaskExecutor(), wakeLock); 105b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mPresenter.onCreate(savedInstanceState); 106b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 107b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 108b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 109b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void onSaveInstanceState(Bundle outState) { 110b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mPresenter.onSaveInstanceState(outState); 111b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson super.onSaveInstanceState(outState); 112b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 113b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 114b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 115b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void onDestroy() { 116b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mPresenter.onDestroy(); 117b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mScheduledExecutorService.shutdown(); 118b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson super.onDestroy(); 119b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 120b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 121c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson @Override 122c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public void onPause() { 123c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mPresenter.onPause(); 124c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson super.onPause(); 125c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson } 126c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson 1276faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private PlaybackViewImpl createPlaybackViewImpl() { 1286faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return new PlaybackViewImpl(new ActivityReference(), getActivity().getApplicationContext(), 1296faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPlaybackLayout); 1306faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 1316faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 132b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson private MediaPlayerProxy createMediaPlayer(ExecutorService executorService) { 133b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson return VariableSpeed.createVariableSpeed(executorService); 134b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 135b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 136b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson private ScheduledExecutorService createScheduledExecutorService() { 137b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson return Executors.newScheduledThreadPool(NUMBER_OF_THREADS_IN_POOL); 138b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 139b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 140b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson /** 141b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * Formats a number of milliseconds as something that looks like {@code 00:05}. 142b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * <p> 143b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * We always use four digits, two for minutes two for seconds. In the very unlikely event 144b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson * that the voicemail duration exceeds 99 minutes, the display is capped at 99 minutes. 145b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson */ 1466faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private static String formatAsMinutesAndSeconds(int millis) { 147b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson int seconds = millis / 1000; 148b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson int minutes = seconds / 60; 149b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson seconds -= minutes * 60; 150b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson if (minutes > 99) { 151b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson minutes = 99; 152b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 153b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson return String.format("%02d:%02d", minutes, seconds); 154b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 155b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 1566faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson /** 1576faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * An object that can provide us with an Activity. 1586faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * <p> 1596faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * Fragments suffer the drawback that the Activity they belong to may sometimes be null. This 1606faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * can happen if the Fragment is detached, for example. In that situation a call to 1616faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * {@link Fragment#getString(int)} will throw and {@link IllegalStateException}. Also, calling 1626faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * {@link Fragment#getActivity()} is dangerous - it may sometimes return null. And thus blindly 1636faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * calling a method on the result of getActivity() is dangerous too. 1646faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * <p> 1656faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * To work around this, I have made the {@link PlaybackViewImpl} class static, so that it does 1666faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * not have access to any Fragment methods directly. Instead it uses an application Context for 1676faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * things like accessing strings, accessing system services. It only uses the Activity when it 1686faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * absolutely needs it - and does so through this class. This makes it easy to see where we have 1696faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson * to check for null properly. 1706faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson */ 1716faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final class ActivityReference { 1726faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson /** Gets this Fragment's Activity: <b>may be null</b>. */ 1736faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public final Activity get() { 1746faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return getActivity(); 1756faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 176b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 177b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 178b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson /** Methods required by the PlaybackView for the VoicemailPlaybackPresenter. */ 1796faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private static final class PlaybackViewImpl implements VoicemailPlaybackPresenter.PlaybackView { 1806faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final ActivityReference mActivityReference; 1816faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final Context mApplicationContext; 1826faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final SeekBar mPlaybackSeek; 1836faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final ImageButton mStartStopButton; 1846faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final ImageButton mPlaybackSpeakerphone; 1856faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final ImageButton mRateDecreaseButton; 1866faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final ImageButton mRateIncreaseButton; 1876faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private final TextViewWithMessagesController mTextController; 1886faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 1896faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public PlaybackViewImpl(ActivityReference activityReference, Context applicationContext, 1906faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson View playbackLayout) { 1916faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson Preconditions.checkNotNull(activityReference); 1926faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson Preconditions.checkNotNull(applicationContext); 1936faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson Preconditions.checkNotNull(playbackLayout); 1946faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mActivityReference = activityReference; 1956faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mApplicationContext = applicationContext; 1966faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPlaybackSeek = (SeekBar) playbackLayout.findViewById(R.id.playback_seek); 1976faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mStartStopButton = (ImageButton) playbackLayout.findViewById( 1986faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson R.id.playback_start_stop); 1996faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPlaybackSpeakerphone = (ImageButton) playbackLayout.findViewById( 2006faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson R.id.playback_speakerphone); 2016faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mRateDecreaseButton = (ImageButton) playbackLayout.findViewById( 2026faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson R.id.rate_decrease_button); 2036faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mRateIncreaseButton = (ImageButton) playbackLayout.findViewById( 2046faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson R.id.rate_increase_button); 2056faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mTextController = new TextViewWithMessagesController( 2066faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson (TextView) playbackLayout.findViewById(R.id.playback_position_text), 2076faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson (TextView) playbackLayout.findViewById(R.id.playback_speed_text)); 2086faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 2096faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 210b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 211b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void finish() { 2126faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson Activity activity = mActivityReference.get(); 2136faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson if (activity != null) { 2146faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson activity.finish(); 2156faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 216b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 217b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 218b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 219b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void runOnUiThread(Runnable runnable) { 2206faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson Activity activity = mActivityReference.get(); 2216faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson if (activity != null) { 2226faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson activity.runOnUiThread(runnable); 2236faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 224b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 225b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 226b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 227b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public Context getDataSourceContext() { 2286faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return mApplicationContext; 229b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 230b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 231b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 232b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void setRateDecreaseButtonListener(View.OnClickListener listener) { 233b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mRateDecreaseButton.setOnClickListener(listener); 234b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 235b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 236b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 237b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void setRateIncreaseButtonListener(View.OnClickListener listener) { 238b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mRateIncreaseButton.setOnClickListener(listener); 239b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 240b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 241b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 242b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void setStartStopListener(View.OnClickListener listener) { 243b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mStartStopButton.setOnClickListener(listener); 244b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 245b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 246b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 247b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void setSpeakerphoneListener(View.OnClickListener listener) { 248b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mPlaybackSpeakerphone.setOnClickListener(listener); 249b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 250b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 251b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 252d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson public void setRateDisplay(float rate, int stringResourceId) { 253d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson mTextController.setTemporaryText( 2546faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mApplicationContext.getString(stringResourceId), 1, TimeUnit.SECONDS); 255b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 256b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 257b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 258b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void setPositionSeekListener(SeekBar.OnSeekBarChangeListener listener) { 259b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mPlaybackSeek.setOnSeekBarChangeListener(listener); 260b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 261b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 262b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 263b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void playbackStarted() { 26439fac71fa6420e4da324c13f141e6956f2837356Hugo Hudson mStartStopButton.setImageResource(R.drawable.ic_hold_pause_holo_dark); 265b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 266b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 267b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 268b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void playbackStopped() { 2695b32cd5d397675fff2189f6b1662695cc33a1348Flavio Lerda mStartStopButton.setImageResource(R.drawable.ic_play); 270b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 271b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 272b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 273fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda public void enableProximitySensor() { 274fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda // Only change the state if the activity is still around. 275fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda Activity activity = mActivityReference.get(); 276fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda if (activity != null && activity instanceof ProximitySensorAware) { 277fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda ((ProximitySensorAware) activity).enableProximitySensor(); 278fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda } 279fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda } 280fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda 281fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda @Override 282fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda public void disableProximitySensor() { 283fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda // Only change the state if the activity is still around. 284fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda Activity activity = mActivityReference.get(); 285fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda if (activity != null && activity instanceof ProximitySensorAware) { 286fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda ((ProximitySensorAware) activity).disableProximitySensor(true); 287fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda } 288fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda } 289fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda 290fd1b98ba83b1ef9b94329f32f0eacf7ddb31cf8bFlavio Lerda @Override 2916faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void registerContentObserver(Uri uri, ContentObserver observer) { 2926faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mApplicationContext.getContentResolver().registerContentObserver(uri, false, observer); 2936faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 2946faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 2956faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 2966faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void unregisterContentObserver(ContentObserver observer) { 2976faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mApplicationContext.getContentResolver().unregisterContentObserver(observer); 2986faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 2996faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3006faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 301d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson public void setClipPosition(int clipPositionInMillis, int clipLengthInMillis) { 302d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson int seekBarPosition = Math.max(0, clipPositionInMillis); 303d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson int seekBarMax = Math.max(seekBarPosition, clipLengthInMillis); 304d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson if (mPlaybackSeek.getMax() != seekBarMax) { 305d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson mPlaybackSeek.setMax(seekBarMax); 306d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 307d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson mPlaybackSeek.setProgress(seekBarPosition); 308d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson mTextController.setPermanentText( 309d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson formatAsMinutesAndSeconds(seekBarMax - seekBarPosition)); 310b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 311b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 3126faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private String getString(int resId) { 3136faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return mApplicationContext.getString(resId); 3146faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3156faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 316b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 31751ada3680de8700bc273a7e652886823f4c1981fHugo Hudson public void setIsBuffering() { 3186faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson disableUiElements(); 3196faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mTextController.setPermanentText(getString(R.string.voicemail_buffering)); 3206faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3216faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3226faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 3236faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void setIsFetchingContent() { 3246faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson disableUiElements(); 3256faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mTextController.setPermanentText(getString(R.string.voicemail_fetching_content)); 3266faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3276faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3286faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 3296faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void setFetchContentTimeout() { 3306faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson disableUiElements(); 3316faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mTextController.setPermanentText(getString(R.string.voicemail_fetching_timout)); 33251ada3680de8700bc273a7e652886823f4c1981fHugo Hudson } 33351ada3680de8700bc273a7e652886823f4c1981fHugo Hudson 33451ada3680de8700bc273a7e652886823f4c1981fHugo Hudson @Override 335b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public int getDesiredClipPosition() { 336b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson return mPlaybackSeek.getProgress(); 337b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 338b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 339b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 3406faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void disableUiElements() { 341757aa55194ba962c71feabe99d47b3021c3f294bHugo Hudson mRateIncreaseButton.setEnabled(false); 342757aa55194ba962c71feabe99d47b3021c3f294bHugo Hudson mRateDecreaseButton.setEnabled(false); 343b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mStartStopButton.setEnabled(false); 3446faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPlaybackSpeakerphone.setEnabled(false); 345b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mPlaybackSeek.setProgress(0); 346b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson mPlaybackSeek.setEnabled(false); 3476faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3486faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3496faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 3506faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void playbackError(Exception e) { 3516faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson disableUiElements(); 35251ada3680de8700bc273a7e652886823f4c1981fHugo Hudson mTextController.setPermanentText(getString(R.string.voicemail_playback_error)); 353757aa55194ba962c71feabe99d47b3021c3f294bHugo Hudson Log.e(TAG, "Could not play voicemail", e); 354b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 355b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 356b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 3576faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void enableUiElements() { 3586faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mRateIncreaseButton.setEnabled(true); 3596faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mRateDecreaseButton.setEnabled(true); 3606faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mStartStopButton.setEnabled(true); 3616faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPlaybackSpeakerphone.setEnabled(true); 3626faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mPlaybackSeek.setEnabled(true); 3636faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3646faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3656faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 3666faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public void sendFetchVoicemailRequest(Uri voicemailUri) { 3676faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson Intent intent = new Intent(VoicemailContract.ACTION_FETCH_VOICEMAIL, voicemailUri); 3686faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson mApplicationContext.sendBroadcast(intent); 3696faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3706faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3716faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 3726faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson public boolean queryHasContent(Uri voicemailUri) { 3736faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson ContentResolver contentResolver = mApplicationContext.getContentResolver(); 3746faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson Cursor cursor = contentResolver.query( 3756faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson voicemailUri, HAS_CONTENT_PROJECTION, null, null, null); 3766faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson try { 3776faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson if (cursor != null && cursor.moveToNext()) { 3786faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return cursor.getInt(cursor.getColumnIndexOrThrow( 3796faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson VoicemailContract.Voicemails.HAS_CONTENT)) == 1; 3806faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3816faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } finally { 3826faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson MoreCloseables.closeQuietly(cursor); 3836faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3846faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return false; 3856faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3866faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3876faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson private AudioManager getAudioManager() { 3886faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson return (AudioManager) mApplicationContext.getSystemService(Context.AUDIO_SERVICE); 3896faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson } 3906faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson 3916faccb8a006eb0c55338eebb34d9dc59af154b14Hugo Hudson @Override 392b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public boolean isSpeakerPhoneOn() { 393b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson return getAudioManager().isSpeakerphoneOn(); 394b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 395b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson 396b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson @Override 397b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson public void setSpeakerPhoneOn(boolean on) { 398b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson getAudioManager().setSpeakerphoneOn(on); 399b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson if (on) { 4002ca7a3830d3284d2736cf708a383efaa73c6d683Flavio Lerda mPlaybackSpeakerphone.setImageResource(R.drawable.ic_speakerphone_on); 401b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } else { 4022ca7a3830d3284d2736cf708a383efaa73c6d683Flavio Lerda mPlaybackSpeakerphone.setImageResource(R.drawable.ic_speakerphone_off); 403b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 404b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 405a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda 406a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda @Override 407a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda public void setVolumeControlStream(int streamType) { 408a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda Activity activity = mActivityReference.get(); 409a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda if (activity != null) { 410a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda activity.setVolumeControlStream(streamType); 411a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda } 412a62438c9a582dd729e00d4577e599674ba2d4672Flavio Lerda } 413b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson } 414d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson 415d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson /** 416d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * Controls a TextView with dynamically changing text. 417d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * <p> 418d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * There are two methods here of interest, 419d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * {@link TextViewWithMessagesController#setPermanentText(String)} and 420d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * {@link TextViewWithMessagesController#setTemporaryText(String, long, TimeUnit)}. The 421d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * former is used to set the text on the text view immediately, and is used in our case for 422d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * the countdown of duration remaining during voicemail playback. The second is used to 423d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * temporarily replace this countdown with a message, in our case faster voicemail speed or 424d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * slower voicemail speed, before returning to the countdown display. 425d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * <p> 426d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson * All the methods on this class must be called from the ui thread. 427d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson */ 428d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson private static final class TextViewWithMessagesController { 42967519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson private static final float VISIBLE = 1; 43067519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson private static final float INVISIBLE = 0; 43167519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson private static final long SHORT_ANIMATION_MS = 200; 43267519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson private static final long LONG_ANIMATION_MS = 400; 433d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson private final Object mLock = new Object(); 43467519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson private final TextView mPermanentTextView; 43567519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson private final TextView mTemporaryTextView; 43667519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson @GuardedBy("mLock") private Runnable mRunnable; 43767519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson 43867519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson public TextViewWithMessagesController(TextView permanentTextView, 43967519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson TextView temporaryTextView) { 44067519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mPermanentTextView = permanentTextView; 44167519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mTemporaryTextView = temporaryTextView; 442d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 443d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson 444d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson public void setPermanentText(String text) { 44567519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mPermanentTextView.setText(text); 446d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 447d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson 448d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson public void setTemporaryText(String text, long duration, TimeUnit units) { 449d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson synchronized (mLock) { 45067519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mTemporaryTextView.setText(text); 45167519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mTemporaryTextView.animate().alpha(VISIBLE).setDuration(SHORT_ANIMATION_MS); 45267519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mPermanentTextView.animate().alpha(INVISIBLE).setDuration(SHORT_ANIMATION_MS); 453d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson mRunnable = new Runnable() { 454d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson @Override 455d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson public void run() { 456d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson synchronized (mLock) { 457d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson // We check for (mRunnable == this) becuase if not true, then another 458d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson // setTemporaryText call has taken place in the meantime, and this 459d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson // one is now defunct and needs to take no action. 460d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson if (mRunnable == this) { 461d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson mRunnable = null; 46267519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mTemporaryTextView.animate() 46367519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson .alpha(INVISIBLE).setDuration(LONG_ANIMATION_MS); 46467519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mPermanentTextView.animate() 46567519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson .alpha(VISIBLE).setDuration(LONG_ANIMATION_MS); 466d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 467d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 468d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 469d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson }; 47067519b221d8a644c40836c15a8ad0a32782fca1fHugo Hudson mTemporaryTextView.postDelayed(mRunnable, units.toMillis(duration)); 471d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 472d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 473d1cac908706366a50bd3ffd71f90334bf812792fHugo Hudson } 474b002f512acfd12b0f25c62579af0b7ecb02d728eHugo Hudson} 475