PageRenderTime 38ms CodeModel.GetById 14ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

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