/documentation/RockLockTutorial/RockLock_01/src/com/marvin/rocklock/RockLockActivity.java
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}