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