PageRenderTime 39ms CodeModel.GetById 14ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/documentation/RockLockTutorial/RockLock_00/src/com/marvin/rocklock/RockLockActivity.java

http://eyes-free.googlecode.com/
Java | 370 lines | 288 code | 43 blank | 39 comment | 48 complexity | 9583d9cd484aeed930189e4a2de1965f MD5 | raw file
  1/*
  2 * Copyright (C) 2010 Google Inc.
  3 * 
  4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5 * use this file except in compliance with the License. You may obtain a copy of
  6 * the License at
  7 * 
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 * 
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 13 * License for the specific language governing permissions and limitations under
 14 * the License.
 15 */
 16
 17package com.marvin.rocklock;
 18
 19import android.app.Activity;
 20import android.content.BroadcastReceiver;
 21import android.content.Context;
 22import android.content.Intent;
 23import android.content.IntentFilter;
 24import android.os.Bundle;
 25import android.telephony.PhoneStateListener;
 26import android.telephony.TelephonyManager;
 27import android.view.KeyEvent;
 28import android.view.MotionEvent;
 29import android.view.View;
 30import android.view.WindowManager;
 31import android.view.View.OnClickListener;
 32import android.view.View.OnTouchListener;
 33import android.view.accessibility.AccessibilityEvent;
 34import android.widget.Button;
 35import android.widget.FrameLayout;
 36import android.widget.TextView;
 37
 38import java.text.SimpleDateFormat;
 39import java.util.Calendar;
 40
 41/**
 42 * The main Rock Lock application that runs as an alternate lock screen which
 43 * enables the user to use stroke gestures to play music. If there is no lock
 44 * pattern, Rock Lock will replace the lock screen entirely; dismissing Rock
 45 * Lock will unlock the phone. If there is a lock pattern, Rock Lock will put up
 46 * the default pattern locked screen when the user dismisses Rock Lock.
 47 * 
 48 * @author clchen@google.com (Charles L. Chen)
 49 */
 50public class RockLockActivity extends Activity {
 51    public static final String EXTRA_STARTED_BY_SERVICE = "STARTED_BY_SERVICE";
 52
 53    private boolean poked = false;
 54
 55    private FrameLayout contentFrame;
 56
 57    private Button unlockButton;
 58
 59    private MusicPlayer mp;
 60
 61    private boolean isSeeking = false;
 62
 63    private boolean seekingStopped = true;
 64
 65    private TextView dateText;
 66
 67    private TextView statusText;
 68
 69    private TextView infoText;
 70
 71    // Catch media button events so that controls from plugged in headsets and
 72    // BlueTooth headsets will work.
 73    //
 74    // Note that this only works if there are NO other apps that are trying to
 75    // consume the media button events and aborting the broadcasts; otherwise,
 76    // whether it works or not is a function of the order in which the
 77    // broadcasts are sent.
 78    private BroadcastReceiver mediaButtonReceiver = new BroadcastReceiver() {
 79        @Override
 80        public void onReceive(Context ctx, Intent data) {
 81            this.abortBroadcast();
 82            KeyEvent event = data.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
 83            int keyCode = event.getKeyCode();
 84            if (event.getAction() == KeyEvent.ACTION_DOWN) {
 85                if ((keyCode == KeyEvent.KEYCODE_HEADSETHOOK)
 86                        || (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)) {
 87                    mp.togglePlayPause();
 88                    updateDisplayText(null, null);
 89                } else if (keyCode == KeyEvent.KEYCODE_MEDIA_NEXT) {
 90                    mp.nextTrack();
 91                    updateDisplayText(null, null);
 92                } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS) {
 93                    mp.prevTrack();
 94                    updateDisplayText(null, null);
 95                }
 96            }
 97        }
 98    };
 99
100    // Don't send any accessibility events since this is a fully self voicing
101    // app.
102    @Override
103    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent evt) {
104        return true;
105    }
106
107    /** Called when the activity is first created. */
108    @Override
109    public void onCreate(Bundle savedInstanceState) {
110        super.onCreate(savedInstanceState);
111
112        // Start the service in case it is not already running
113        startService(new Intent(this, ScreenOnHandlerService.class));
114
115        requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
116        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
117
118        setContentView(R.layout.main);
119
120        mp = new MusicPlayer(this);
121
122        final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
123        tm.listen(new PhoneStateListener() {
124            @Override
125            public void onCallStateChanged(int state, String incomingNumber) {
126                // If the phone is not idle, immediately quit and let the
127                // default lock screen handle it.
128                if (state != TelephonyManager.CALL_STATE_IDLE) {
129                    finish();
130                    return;
131                }
132            }
133        }, PhoneStateListener.LISTEN_CALL_STATE);
134
135        unlockButton = (Button) findViewById(R.id.unlockButton);
136        unlockButton.setOnClickListener(new OnClickListener() {
137            @Override
138            public void onClick(View arg0) {
139                dismissSlideUnlockScreen();
140            }
141        });
142
143        IntentFilter filter = new IntentFilter();
144        filter.addAction(Intent.ACTION_MEDIA_BUTTON);
145        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
146        registerReceiver(mediaButtonReceiver, filter);
147
148        contentFrame = (FrameLayout) findViewById(R.id.contentFrame);
149        View buttonLayer = this.getLayoutInflater().inflate(R.layout.buttonlayer, null);
150        dateText = (TextView) buttonLayer.findViewById(R.id.dateText);
151        statusText = (TextView) buttonLayer.findViewById(R.id.statusText);
152        infoText = (TextView) buttonLayer.findViewById(R.id.infoText);
153
154        Button prevArtistButton = (Button) buttonLayer.findViewById(R.id.prevArtistButton);
155        prevArtistButton.setOnClickListener(new OnClickListener() {
156            @Override
157            public void onClick(View arg0) {
158                poked = true;
159                mp.prevArtist();
160                updateDisplayText(null, null);
161            }
162        });
163
164        Button prevAlbumButton = (Button) buttonLayer.findViewById(R.id.prevAlbumButton);
165        prevAlbumButton.setOnClickListener(new OnClickListener() {
166            @Override
167            public void onClick(View arg0) {
168                poked = true;
169                mp.prevAlbum();
170                updateDisplayText(null, null);
171            }
172        });
173
174        Button nextArtistButton = (Button) buttonLayer.findViewById(R.id.nextArtistButton);
175        nextArtistButton.setOnClickListener(new OnClickListener() {
176            @Override
177            public void onClick(View arg0) {
178                poked = true;
179                mp.nextArtist();
180                updateDisplayText(null, null);
181            }
182        });
183
184        Button prevTrackButton = (Button) buttonLayer.findViewById(R.id.prevTrackButton);
185        prevTrackButton.setOnClickListener(new OnClickListener() {
186            @Override
187            public void onClick(View arg0) {
188                poked = true;
189                mp.prevTrack();
190                updateDisplayText(null, null);
191            }
192        });
193
194        Button nextTrackButton = (Button) buttonLayer.findViewById(R.id.nextTrackButton);
195        nextTrackButton.setOnClickListener(new OnClickListener() {
196            @Override
197            public void onClick(View arg0) {
198                poked = true;
199                mp.nextTrack();
200                updateDisplayText(null, null);
201            }
202        });
203
204        Button rewButton = (Button) buttonLayer.findViewById(R.id.rewButton);
205        rewButton.setOnTouchListener(new OnTouchListener() {
206            @Override
207            public boolean onTouch(View v, MotionEvent event) {
208                poked = true;
209                if (event.getAction() == MotionEvent.ACTION_DOWN) {
210                    if (seekingStopped) {
211                        updateDisplayText(getString(R.string.rewind), mp.getCurrentSongInfo());
212                        isSeeking = true;
213                        new Thread(new Seeker(-1)).start();
214                    }
215                } else if (event.getAction() == MotionEvent.ACTION_UP) {
216                    isSeeking = false;
217                    updateDisplayText(null, null);
218                }
219                return true;
220            }
221        });
222
223        Button nextAlbumButton = (Button) buttonLayer.findViewById(R.id.nextAlbumButton);
224        nextAlbumButton.setOnClickListener(new OnClickListener() {
225            @Override
226            public void onClick(View arg0) {
227                poked = true;
228                mp.nextAlbum();
229                updateDisplayText(null, null);
230            }
231        });
232
233        Button ffButton = (Button) buttonLayer.findViewById(R.id.ffButton);
234        ffButton.setOnTouchListener(new OnTouchListener() {
235            @Override
236            public boolean onTouch(View v, MotionEvent event) {
237                poked = true;
238                if (event.getAction() == MotionEvent.ACTION_DOWN) {
239                    if (seekingStopped) {
240                        updateDisplayText(getString(R.string.fast_forward), mp.getCurrentSongInfo());
241                        isSeeking = true;
242                        new Thread(new Seeker(1)).start();
243                    }
244                } else if (event.getAction() == MotionEvent.ACTION_UP) {
245                    isSeeking = false;
246                    updateDisplayText(null, null);
247                }
248                return true;
249            }
250        });
251
252        Button playPauseButton = (Button) buttonLayer.findViewById(R.id.playPauseButton);
253        playPauseButton.setOnClickListener(new OnClickListener() {
254            @Override
255            public void onClick(View arg0) {
256                poked = true;
257                mp.togglePlayPause();
258                updateDisplayText(null, null);
259            }
260        });
261
262        contentFrame.addView(buttonLayer);
263    }
264
265    @Override
266    public void onResume() {
267        super.onResume();
268        poked = false;
269        Calendar cal = Calendar.getInstance();
270        int day = cal.get(Calendar.DAY_OF_MONTH);
271        SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
272        String monthStr = monthFormat.format(cal.getTime());
273        int year = cal.get(Calendar.YEAR);
274        dateText.setText(monthStr + " " + Integer.toString(day) + ", " + year);
275        new Thread(new PokeWatcher()).start();
276    }
277
278    @Override
279    public boolean onKeyDown(int keyCode, KeyEvent event) {
280        if (keyCode == KeyEvent.KEYCODE_BACK) {
281            dismissSlideUnlockScreen();
282            return true;
283        }
284        if (keyCode == KeyEvent.KEYCODE_MENU) {
285            mp.stop();
286            int songPickerType = mp.cycleSongPicker();
287            int songPickerTextResId = R.string.tagged_music_playlist;
288            if (songPickerType == MusicPlayer.ROCKLOCK_PLAYLIST) {
289                songPickerTextResId = R.string.rock_lock_playlist;
290            }
291            updateDisplayText(getString(R.string.app_name), getString(songPickerTextResId));
292            return true;
293        }
294        return super.onKeyDown(keyCode, event);
295    }
296
297    @Override
298    public void onDestroy() {
299        super.onDestroy();
300        poked = true;
301        mp.stop();
302        unregisterReceiver(mediaButtonReceiver);
303    }
304
305    public void updateDisplayText(String status, String info) {
306        if ((status == null) || (info == null)) {
307            if (mp.isPlaying()) {
308                statusText.setText(R.string.playing);
309                infoText.setText(mp.getCurrentSongInfo());
310            } else {
311                statusText.setText(R.string.app_name);
312                infoText.setText("The lock that rocks!");
313            }
314            return;
315        }
316        statusText.setText(status);
317        infoText.setText(info);
318    }
319
320    private class Seeker implements Runnable {
321        private int seekMode = 0;
322
323        public Seeker(int seekDirection) {
324            seekMode = seekDirection;
325        }
326
327        @Override
328        public void run() {
329            while (isSeeking) {
330                try {
331                    Thread.sleep(100);
332                } catch (InterruptedException e) {
333                    e.printStackTrace();
334                }
335                if (seekMode == 1) {
336                    mp.seekForward();
337                } else if (seekMode == -1) {
338                    mp.seekBackward();
339                }
340            }
341            seekingStopped = true;
342        }
343    }
344
345    private class PokeWatcher implements Runnable {
346        @Override
347        public void run() {
348            try {
349                Thread.sleep(10000);
350            } catch (InterruptedException e) {
351                e.printStackTrace();
352            }
353            if (!poked && (mp != null) && !mp.isPlaying()) {
354                finish();
355            }
356        }
357    }
358    
359    private void dismissSlideUnlockScreen() {
360        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
361        // finish() must be called in another thread or else the addFlags
362        // call in the previous line will not take effect.
363        new Thread(new Runnable() {
364            @Override
365            public void run() {
366                finish();
367            }
368        }).start();
369    }
370}