PageRenderTime 66ms CodeModel.GetById 15ms app.highlight 46ms RepoModel.GetById 2ms app.codeStats 0ms

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

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