PageRenderTime 36ms CodeModel.GetById 16ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

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

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