15cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson/*
25cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * Copyright (C) 2012 The Android Open Source Project
35cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson *
45cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * Licensed under the Apache License, Version 2.0 (the "License");
55cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * you may not use this file except in compliance with the License.
65cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * You may obtain a copy of the License at
75cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson *
85cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson *      http://www.apache.org/licenses/LICENSE-2.0
95cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson *
105cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * Unless required by applicable law or agreed to in writing, software
115cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * distributed under the License is distributed on an "AS IS" BASIS,
125cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * See the License for the specific language governing permissions and
145cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * limitations under the License.
155cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson */
165cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
175cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonpackage com.android.deskclock;
185cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
195cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.app.Service;
205cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.content.Context;
215cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.content.Intent;
225cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.content.res.AssetFileDescriptor;
235cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.content.res.Resources;
245cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.media.AudioManager;
255cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.media.MediaPlayer;
265cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.media.MediaPlayer.OnErrorListener;
275cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.os.IBinder;
285cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.telephony.PhoneStateListener;
295cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport android.telephony.TelephonyManager;
305cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
315cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson/**
325cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson * Play the timer's ringtone. Will continue playing the same alarm until service is stopped.
335cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson */
34205f02bc332c272cd43a2466578ac741bc700d10Alon Albertpublic class TimerRingService extends Service implements AudioManager.OnAudioFocusChangeListener {
355cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
365cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private boolean mPlaying = false;
375cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private MediaPlayer mMediaPlayer;
385cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private TelephonyManager mTelephonyManager;
395cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private int mInitialCallState;
405cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
415cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
425cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
435cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        @Override
445cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        public void onCallStateChanged(int state, String ignored) {
455cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // The user might already be in a call when the alarm fires. When
465cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // we register onCallStateChanged, we get the initial in-call state
475cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // which kills the alarm. Check against the initial call state so
485cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // we don't kill the alarm during a call.
495cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            if (state != TelephonyManager.CALL_STATE_IDLE
505cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                    && state != mInitialCallState) {
515cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                stopSelf();
525cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            }
535cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        }
545cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    };
555cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
565cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    @Override
575cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    public void onCreate() {
585cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // Listen for incoming calls to kill the alarm.
595cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        mTelephonyManager =
605cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
615cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        mTelephonyManager.listen(
625cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
635aee14904f3b7272b5a1741fe820a8ed73b96664Robyn Coultas        AlarmAlertWakeLock.acquireScreenCpuWakeLock(this);
645cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
655cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
665cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    @Override
675cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    public void onDestroy() {
685cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        stop();
695cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // Stop listening for incoming calls.
705cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        mTelephonyManager.listen(mPhoneStateListener, 0);
715cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        AlarmAlertWakeLock.releaseCpuLock();
725cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
735cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
745cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    @Override
755cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    public IBinder onBind(Intent intent) {
765cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        return null;
775cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
785cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
795cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    @Override
805cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    public int onStartCommand(Intent intent, int flags, int startId) {
815cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // No intent, tell the system not to restart us.
825cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        if (intent == null) {
835cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            stopSelf();
845cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            return START_NOT_STICKY;
855cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        }
865cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
875cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        play();
885cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // Record the initial call state here so that the new alarm has the
895cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // newest state.
905cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        mInitialCallState = mTelephonyManager.getCallState();
915cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
925cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        return START_STICKY;
935cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
945cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
955cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    // Volume suggested by media team for in-call alarms.
965cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private static final float IN_CALL_VOLUME = 0.125f;
975cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
985cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private void play() {
995cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1005cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        if (mPlaying) {
1015cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            return;
1025cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        }
1035cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
104cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen        LogUtils.v("TimerRingService.play()");
1055cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1065cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // TODO: Reuse mMediaPlayer instead of creating a new one and/or use
1075cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // RingtoneManager.
1085cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        mMediaPlayer = new MediaPlayer();
1095cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        mMediaPlayer.setOnErrorListener(new OnErrorListener() {
1105cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            @Override
1115cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            public boolean onError(MediaPlayer mp, int what, int extra) {
112cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen                LogUtils.e("Error occurred while playing audio.");
1135cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mp.stop();
1145cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mp.release();
1155cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mMediaPlayer = null;
1165cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                return true;
1175cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            }
1185cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        });
1195cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1205cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        try {
1215cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // Check if we are in a call. If we are, use the in-call alarm
1225cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // resource at a low volume to not disrupt the call.
1235cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            if (mTelephonyManager.getCallState()
1245cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                    != TelephonyManager.CALL_STATE_IDLE) {
125cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen                LogUtils.v("Using the in-call alarm");
1265cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mMediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME);
1275cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                setDataSourceFromResource(getResources(), mMediaPlayer,
1285cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                        R.raw.in_call_alarm);
1295cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            } else {
130f98a82ceff862cde3b0a0440e6c3889db377d897Isaac Katzenelson                AssetFileDescriptor afd = getAssets().openFd("sounds/Timer_Expire.ogg");
131f98a82ceff862cde3b0a0440e6c3889db377d897Isaac Katzenelson                mMediaPlayer.setDataSource(
132f98a82ceff862cde3b0a0440e6c3889db377d897Isaac Katzenelson                        afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
1335cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            }
1345cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            startAlarm(mMediaPlayer);
1355cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        } catch (Exception ex) {
136cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen            LogUtils.v("Using the fallback ringtone");
1375cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // The alert may be on the sd card which could be busy right
1385cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // now. Use the fallback ringtone.
1395cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            try {
1405cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                // Must reset the media player to clear the error state.
1415cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mMediaPlayer.reset();
1425cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                setDataSourceFromResource(getResources(), mMediaPlayer,
1435cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                        R.raw.fallbackring);
1445cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                startAlarm(mMediaPlayer);
1455cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            } catch (Exception ex2) {
1465cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                // At this point we just don't play anything.
147cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen                LogUtils.e("Failed to play fallback ringtone", ex2);
1485cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            }
1495cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        }
1505cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1515cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        mPlaying = true;
1525cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
1535cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1545cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    // Do the common stuff when starting the alarm.
1555cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private void startAlarm(MediaPlayer player)
1565cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            throws java.io.IOException, IllegalArgumentException,
1575cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                   IllegalStateException {
1585cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        final AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
1595cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // do not play alarms if stream volume is 0
1605cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        // (typically because ringer mode is silent).
1615cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
1625cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            player.setAudioStreamType(AudioManager.STREAM_ALARM);
1635cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            player.setLooping(true);
1645cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            player.prepare();
165205f02bc332c272cd43a2466578ac741bc700d10Alon Albert            audioManager.requestAudioFocus(
166205f02bc332c272cd43a2466578ac741bc700d10Alon Albert                    this, AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
1675cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            player.start();
1685cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        }
1695cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
1705cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1715cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    private void setDataSourceFromResource(Resources resources,
1725cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            MediaPlayer player, int res) throws java.io.IOException {
1735cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        AssetFileDescriptor afd = resources.openRawResourceFd(res);
1745cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        if (afd != null) {
1755cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
1765cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                    afd.getLength());
1775cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            afd.close();
1785cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        }
1795cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
1805cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1815cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    /**
18258c329f52d7952597ae7a4e88fc2ec9e15ddd93aRobyn Coultas     * Stops timer audio
1835cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson     */
1845cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    public void stop() {
185cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen        LogUtils.v("TimerRingService.stop()");
1865cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        if (mPlaying) {
1875cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            mPlaying = false;
1885cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
1895cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            // Stop audio playing
1905cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            if (mMediaPlayer != null) {
1915cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mMediaPlayer.stop();
192205f02bc332c272cd43a2466578ac741bc700d10Alon Albert                final AudioManager audioManager =
193205f02bc332c272cd43a2466578ac741bc700d10Alon Albert                        (AudioManager)getSystemService(Context.AUDIO_SERVICE);
194205f02bc332c272cd43a2466578ac741bc700d10Alon Albert                audioManager.abandonAudioFocus(this);
1955cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mMediaPlayer.release();
1965cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson                mMediaPlayer = null;
1975cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            }
1985cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson        }
1995cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson    }
2005cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
2015cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson
202205f02bc332c272cd43a2466578ac741bc700d10Alon Albert    @Override
203205f02bc332c272cd43a2466578ac741bc700d10Alon Albert    public void onAudioFocusChange(int focusChange) {
204205f02bc332c272cd43a2466578ac741bc700d10Alon Albert        // Do nothing
205205f02bc332c272cd43a2466578ac741bc700d10Alon Albert    }
2065cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson}
207