StopwatchFragment.java revision e40b31200dee36341e5697b2774799555ca79c9b
1package com.android.deskclock.stopwatch; 2 3import android.app.Activity; 4import android.content.Context; 5import android.content.Intent; 6import android.content.SharedPreferences; 7import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 8import android.content.pm.PackageManager; 9import android.content.pm.ResolveInfo; 10import android.graphics.drawable.Drawable; 11import android.os.Bundle; 12import android.preference.PreferenceManager; 13import android.view.LayoutInflater; 14import android.view.View; 15import android.view.ViewGroup; 16import android.widget.AdapterView; 17import android.widget.AdapterView.OnItemClickListener; 18import android.widget.ArrayAdapter; 19import android.widget.BaseAdapter; 20import android.widget.Button; 21import android.widget.ImageButton; 22import android.widget.ImageView; 23import android.widget.ListPopupWindow; 24import android.widget.ListView; 25import android.widget.PopupWindow.OnDismissListener; 26import android.widget.TextView; 27 28import com.android.deskclock.CircleTimerView; 29import com.android.deskclock.DeskClockFragment; 30import com.android.deskclock.Log; 31import com.android.deskclock.R; 32import com.android.deskclock.Utils; 33import com.android.deskclock.timer.CountingTimerView; 34 35import java.util.ArrayList; 36import java.util.List; 37 38/** 39 * TODO: Insert description here. (generated by isaackatz) 40 */ 41public class StopwatchFragment extends DeskClockFragment implements OnSharedPreferenceChangeListener{ 42 int mState = Stopwatches.STOPWATCH_RESET; 43 44 // Stopwatch views that are accessed by the activity 45 private ImageButton mLeftButton, mRightButton; 46 private CircleTimerView mTime; 47 private CountingTimerView mTimeText; 48 private ListView mLapsList; 49 private ImageButton mShareButton; 50 private ListPopupWindow mSharePopup; 51 52 // Used for calculating the time from the start taking into account the pause times 53 long mStartTime = 0; 54 long mAccumulatedTime = 0; 55 56 // Lap information 57 class Lap { 58 Lap () { 59 mLapTime = 0; 60 mTotalTime = 0; 61 } 62 63 Lap (long time, long total) { 64 mLapTime = time; 65 mTotalTime = total; 66 } 67 public long mLapTime; 68 public long mTotalTime; 69 } 70 71 // Adapter for the ListView that shows the lap times. 72 class LapsListAdapter extends BaseAdapter { 73 74 ArrayList<Lap> mLaps = new ArrayList<Lap>(); 75 private final LayoutInflater mInflater; 76 77 public LapsListAdapter(Context context) { 78 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 79 } 80 81 @Override 82 public long getItemId(int position) { 83 return position; 84 } 85 86 @Override 87 public View getView(int position, View convertView, ViewGroup parent) { 88 if (mLaps.size() == 0 || position >= mLaps.size()) { 89 return null; 90 } 91 View lapInfo; 92 if (convertView != null) { 93 lapInfo = convertView; 94 } else { 95 lapInfo = mInflater.inflate(R.layout.lap_view, parent, false); 96 } 97 TextView count = (TextView)lapInfo.findViewById(R.id.lap_number); 98 TextView lapTime = (TextView)lapInfo.findViewById(R.id.lap_time); 99 TextView toalTime = (TextView)lapInfo.findViewById(R.id.lap_total); 100 lapTime.setText(Stopwatches.getTimeText(mLaps.get(position).mLapTime)); 101 toalTime.setText(Stopwatches.getTimeText(mLaps.get(position).mTotalTime)); 102 count.setText(getString(R.string.sw_current_lap_number, mLaps.size() - position)); 103 return lapInfo; 104 105 } 106 107 @Override 108 public int getCount() { 109 return mLaps.size(); 110 } 111 112 @Override 113 public Object getItem(int position) { 114 if (mLaps.size() == 0 || position >= mLaps.size()) { 115 return null; 116 } 117 return mLaps.get(position); 118 } 119 120 public void addLap(Lap l) { 121 mLaps.add(0, l); 122 notifyDataSetChanged(); 123 } 124 125 public void clearLaps() { 126 mLaps.clear(); 127 notifyDataSetChanged(); 128 } 129 130 // Helper function used to get the lap data to be stored in the activitys's bundle 131 public long [] getLapTimes() { 132 int size = mLaps.size(); 133 if (size == 0) { 134 return null; 135 } 136 long [] laps = new long[size]; 137 for (int i = 0; i < size; i ++) { 138 laps[i] = mLaps.get(i).mTotalTime; 139 } 140 return laps; 141 } 142 143 // Helper function to restore adapter's data from the activity's bundle 144 public void setLapTimes(long [] laps) { 145 if (laps == null || laps.length == 0) { 146 return; 147 } 148 149 int size = laps.length; 150 mLaps.clear(); 151 for (int i = 0; i < size; i ++) { 152 mLaps.add(new Lap (laps[i], 0)); 153 } 154 long totalTime = 0; 155 for (int i = size -1; i >= 0; i --) { 156 totalTime += laps[i]; 157 mLaps.get(i).mTotalTime = totalTime; 158 } 159 notifyDataSetChanged(); 160 } 161 } 162 163 // Keys for data stored in the activity's bundle 164 private static final String START_TIME_KEY = "start_time"; 165 private static final String ACCUM_TIME_KEY = "accum_time"; 166 private static final String STATE_KEY = "state"; 167 private static final String LAPS_KEY = "laps"; 168 169 LapsListAdapter mLapsAdapter; 170 171 public StopwatchFragment() { 172 } 173 174 private void rightButtonAction() { 175 long time = Utils.getTimeNow(); 176 Context context = getActivity().getApplicationContext(); 177 Intent intent = new Intent(context, StopwatchService.class); 178 intent.putExtra(Stopwatches.MESSAGE_TIME, time); 179 intent.putExtra(Stopwatches.SHOW_NOTIF, false); 180 buttonClicked(true); 181 switch (mState) { 182 case Stopwatches.STOPWATCH_RUNNING: 183 // do stop 184 long curTime = Utils.getTimeNow(); 185 mAccumulatedTime += (curTime - mStartTime); 186 doStop(); 187 intent.setAction(Stopwatches.STOP_STOPWATCH); 188 context.startService(intent); 189 break; 190 case Stopwatches.STOPWATCH_RESET: 191 case Stopwatches.STOPWATCH_STOPPED: 192 // do start 193 doStart(time); 194 intent.setAction(Stopwatches.START_STOPWATCH); 195 context.startService(intent); 196 break; 197 default: 198 Log.wtf("Illegal state " + mState 199 + " while pressing the right stopwatch button"); 200 break; 201 } 202 } 203 204 @Override 205 public View onCreateView(LayoutInflater inflater, ViewGroup container, 206 Bundle savedInstanceState) { 207 // Inflate the layout for this fragment 208 View v = inflater.inflate(R.layout.stopwatch_fragment, container, false); 209 210 mLeftButton = (ImageButton)v.findViewById(R.id.stopwatch_left_button); 211 mLeftButton.setOnClickListener(new View.OnClickListener() { 212 @Override 213 public void onClick(View v) { 214 long time = Utils.getTimeNow(); 215 Context context = getActivity().getApplicationContext(); 216 Intent intent = new Intent(context, StopwatchService.class); 217 intent.putExtra(Stopwatches.MESSAGE_TIME, time); 218 intent.putExtra(Stopwatches.SHOW_NOTIF, false); 219 buttonClicked(true); 220 switch (mState) { 221 case Stopwatches.STOPWATCH_RUNNING: 222 // Save lap time 223 addLapTime(time); 224 doLap(); 225 intent.setAction(Stopwatches.LAP_STOPWATCH); 226 context.startService(intent); 227 break; 228 case Stopwatches.STOPWATCH_STOPPED: 229 // do reset 230 doReset(); 231 intent.setAction(Stopwatches.RESET_STOPWATCH); 232 context.startService(intent); 233 break; 234 default: 235 Log.wtf("Illegal state " + mState 236 + " while pressing the left stopwatch button"); 237 break; 238 } 239 } 240 }); 241 242 243 mRightButton = (ImageButton)v.findViewById(R.id.stopwatch_right_button); 244 mRightButton.setOnClickListener(new View.OnClickListener() { 245 @Override 246 public void onClick(View v) { 247 rightButtonAction(); 248 } 249 }); 250 mShareButton = (ImageButton)v.findViewById(R.id.stopwatch_share_button); 251 252 mShareButton.setOnClickListener(new View.OnClickListener() { 253 @Override 254 public void onClick(View v) { 255 showSharePopup(); 256 } 257 }); 258 259 // Timer text serves as a virtual start/stop button. 260 final CountingTimerView countingTimerView = (CountingTimerView) 261 v.findViewById(R.id.stopwatch_time_text); 262 countingTimerView.registerVirtualButtonAction(new Runnable() { 263 @Override 264 public void run() { 265 rightButtonAction(); 266 } 267 }); 268 countingTimerView.setVirtualButtonEnabled(true); 269 270 mTime = (CircleTimerView)v.findViewById(R.id.stopwatch_time); 271 mTimeText = (CountingTimerView)v.findViewById(R.id.stopwatch_time_text); 272 mLapsList = (ListView)v.findViewById(R.id.laps_list); 273 mLapsList.setDividerHeight(0); 274 mLapsAdapter = new LapsListAdapter(getActivity()); 275 if (mLapsList != null) { 276 mLapsList.setAdapter(mLapsAdapter); 277 } 278 279 return v; 280 } 281 282 @Override 283 public void onResume() { 284 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); 285 prefs.registerOnSharedPreferenceChangeListener(this); 286 readFromSharedPref(prefs); 287 mTime.readFromSharedPref(prefs, "sw"); 288 mTime.postInvalidate(); 289 290 setButtons(mState); 291 mTimeText.setTime(mAccumulatedTime, true, true); 292 if (mState == Stopwatches.STOPWATCH_RUNNING) { 293 startUpdateThread(); 294 } else if (mState == Stopwatches.STOPWATCH_STOPPED && mAccumulatedTime != 0) { 295 mTimeText.blinkTimeStr(true); 296 } 297 showLaps(); 298 299 super.onResume(); 300 } 301 302 @Override 303 public void onPause() { 304 if (mState == Stopwatches.STOPWATCH_RUNNING) { 305 stopUpdateThread(); 306 } 307 // The stopwatch must keep running even if the user closes the app so save stopwatch state 308 // in shared prefs 309 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); 310 prefs.unregisterOnSharedPreferenceChangeListener(this); 311 writeToSharedPref(prefs); 312 mTime.writeToSharedPref(prefs, "sw"); 313 mTimeText.blinkTimeStr(false); 314 if (mSharePopup != null) { 315 mSharePopup.dismiss(); 316 mSharePopup = null; 317 } 318 319 super.onPause(); 320 } 321 322 private void doStop() { 323 stopUpdateThread(); 324 mTime.pauseIntervalAnimation(); 325 mTimeText.setTime(mAccumulatedTime, true, true); 326 mTimeText.blinkTimeStr(true); 327 updateCurrentLap(mAccumulatedTime); 328 setButtons(Stopwatches.STOPWATCH_STOPPED); 329 mState = Stopwatches.STOPWATCH_STOPPED; 330 } 331 332 private void doStart(long time) { 333 mStartTime = time; 334 startUpdateThread(); 335 mTimeText.blinkTimeStr(false); 336 if (mTime.isAnimating()) { 337 mTime.startIntervalAnimation(); 338 } 339 setButtons(Stopwatches.STOPWATCH_RUNNING); 340 mState = Stopwatches.STOPWATCH_RUNNING; 341 } 342 343 private void doLap() { 344 showLaps(); 345 setButtons(Stopwatches.STOPWATCH_RUNNING); 346 } 347 348 private void doReset() { 349 SharedPreferences prefs = 350 PreferenceManager.getDefaultSharedPreferences(getActivity()); 351 clearSharedPref(prefs); 352 mTime.clearSharedPref(prefs, "sw"); 353 mAccumulatedTime = 0; 354 mLapsAdapter.clearLaps(); 355 showLaps(); 356 mTime.stopIntervalAnimation(); 357 mTime.reset(); 358 mTimeText.setTime(mAccumulatedTime, true, true); 359 mTimeText.blinkTimeStr(false); 360 setButtons(Stopwatches.STOPWATCH_RESET); 361 mState = Stopwatches.STOPWATCH_RESET; 362 } 363 364 private void showShareButton(boolean show) { 365 if (mShareButton != null) { 366 mShareButton.setVisibility(show ? View.VISIBLE : View.INVISIBLE); 367 mShareButton.setEnabled(show); 368 } 369 } 370 371 private void showSharePopup() { 372 Intent intent = getShareIntent(); 373 374 Activity parent = getActivity(); 375 PackageManager packageManager = parent.getPackageManager(); 376 377 // Get a list of sharable options. 378 List<ResolveInfo> shareOptions = packageManager 379 .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); 380 381 if (shareOptions.size() == 0) { 382 return; 383 } 384 ArrayList<CharSequence> shareOptionTitles = new ArrayList<CharSequence>(); 385 ArrayList<Drawable> shareOptionIcons = new ArrayList<Drawable>(); 386 ArrayList<CharSequence> shareOptionThreeTitles = new ArrayList<CharSequence>(); 387 ArrayList<Drawable> shareOptionThreeIcons = new ArrayList<Drawable>(); 388 ArrayList<String> shareOptionPackageNames = new ArrayList<String>(); 389 ArrayList<String> shareOptionClassNames = new ArrayList<String>(); 390 391 for (int option_i = 0; option_i < shareOptions.size(); option_i++) { 392 ResolveInfo option = shareOptions.get(option_i); 393 CharSequence label = option.loadLabel(packageManager); 394 Drawable icon = option.loadIcon(packageManager); 395 shareOptionTitles.add(label); 396 shareOptionIcons.add(icon); 397 if (shareOptions.size() > 4 && option_i < 3) { 398 shareOptionThreeTitles.add(label); 399 shareOptionThreeIcons.add(icon); 400 } 401 shareOptionPackageNames.add(option.activityInfo.packageName); 402 shareOptionClassNames.add(option.activityInfo.name); 403 } 404 if (shareOptionTitles.size() > 4) { 405 shareOptionThreeTitles.add(getResources().getString(R.string.see_all)); 406 shareOptionThreeIcons.add(getResources().getDrawable(android.R.color.transparent)); 407 } 408 409 if (mSharePopup != null) { 410 mSharePopup.dismiss(); 411 mSharePopup = null; 412 } 413 mSharePopup = new ListPopupWindow(parent); 414 mSharePopup.setAnchorView(mShareButton); 415 mSharePopup.setModal(true); 416 // This adapter to show the rest will be used to quickly repopulate if "See all..." is hit. 417 ImageLabelAdapter showAllAdapter = new ImageLabelAdapter(parent, 418 R.layout.popup_window_item, shareOptionTitles, shareOptionIcons, 419 shareOptionPackageNames, shareOptionClassNames); 420 if (shareOptionTitles.size() > 4) { 421 mSharePopup.setAdapter(new ImageLabelAdapter(parent, R.layout.popup_window_item, 422 shareOptionThreeTitles, shareOptionThreeIcons, shareOptionPackageNames, 423 shareOptionClassNames, showAllAdapter)); 424 } else { 425 mSharePopup.setAdapter(showAllAdapter); 426 } 427 428 mSharePopup.setOnItemClickListener(new OnItemClickListener() { 429 @Override 430 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 431 CharSequence label = ((TextView) view.findViewById(R.id.title)).getText(); 432 if (label.equals(getResources().getString(R.string.see_all))) { 433 mSharePopup.setAdapter( 434 ((ImageLabelAdapter) parent.getAdapter()).getShowAllAdapter()); 435 mSharePopup.show(); 436 return; 437 } 438 439 Intent intent = getShareIntent(); 440 ImageLabelAdapter adapter = (ImageLabelAdapter) parent.getAdapter(); 441 String packageName = adapter.getPackageName(position); 442 String className = adapter.getClassName(position); 443 intent.setClassName(packageName, className); 444 startActivity(intent); 445 } 446 }); 447 mSharePopup.setOnDismissListener(new OnDismissListener() { 448 @Override 449 public void onDismiss() { 450 mSharePopup = null; 451 } 452 }); 453 mSharePopup.setWidth((int) getResources().getDimension(R.dimen.popup_window_width)); 454 mSharePopup.show(); 455 } 456 457 private Intent getShareIntent() { 458 Intent intent = new Intent(android.content.Intent.ACTION_SEND); 459 intent.setType("text/plain"); 460 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 461 intent.putExtra(Intent.EXTRA_SUBJECT, 462 Stopwatches.getShareTitle(getActivity().getApplicationContext())); 463 intent.putExtra(Intent.EXTRA_TEXT, Stopwatches.buildShareResults( 464 getActivity().getApplicationContext(), mTimeText.getTimeString(), 465 getLapShareTimes(mLapsAdapter.getLapTimes()))); 466 return intent; 467 } 468 469 /** Turn laps as they would be saved in prefs into format for sharing. **/ 470 private long[] getLapShareTimes(long[] input) { 471 if (input == null) { 472 return null; 473 } 474 475 int numLaps = input.length; 476 long[] output = new long[numLaps]; 477 long prevLapElapsedTime = 0; 478 for (int lap_i = numLaps - 1; lap_i >= 0; lap_i--) { 479 long lap = input[lap_i]; 480 Log.v("lap "+lap_i+": "+lap); 481 output[lap_i] = lap - prevLapElapsedTime; 482 prevLapElapsedTime = lap; 483 } 484 return output; 485 } 486 487 /*** 488 * Update the buttons on the stopwatch according to the watch's state 489 */ 490 private void setButtons(int state) { 491 switch (state) { 492 case Stopwatches.STOPWATCH_RESET: 493 setButton(mLeftButton, R.string.sw_lap_button, R.drawable.ic_lap_normal, false, 494 View.INVISIBLE); 495 setButton(mRightButton, R.string.sw_start_button, R.drawable.ic_start_normal, true, 496 View.VISIBLE); 497 showShareButton(false); 498 break; 499 case Stopwatches.STOPWATCH_RUNNING: 500 setButton(mLeftButton, R.string.sw_lap_button, R.drawable.ic_lap_normal, 501 !reachedMaxLaps(), View.VISIBLE); 502 setButton(mRightButton, R.string.sw_stop_button, R.drawable.ic_stop_normal, true, 503 View.VISIBLE); 504 showShareButton(false); 505 break; 506 case Stopwatches.STOPWATCH_STOPPED: 507 setButton(mLeftButton, R.string.sw_reset_button, R.drawable.ic_reset_normal, true, 508 View.VISIBLE); 509 setButton(mRightButton, R.string.sw_start_button, R.drawable.ic_start_normal, true, 510 View.VISIBLE); 511 showShareButton(true); 512 break; 513 default: 514 break; 515 } 516 } 517 private boolean reachedMaxLaps() { 518 return mLapsAdapter.getCount() >= Stopwatches.MAX_LAPS; 519 } 520 521 /*** 522 * Set a single button with the string and states provided. 523 * @param b - Button view to update 524 * @param text - Text in button 525 * @param enabled - enable/disables the button 526 * @param visibility - Show/hide the button 527 */ 528 private void setButton( 529 ImageButton b, int text, int drawableId, boolean enabled, int visibility) { 530 b.setContentDescription(getActivity().getResources().getString(text)); 531 b.setImageResource(drawableId); 532 b.setVisibility(visibility); 533 b.setEnabled(enabled); 534 } 535 536 /*** 537 * 538 * @param time - in hundredths of a second 539 */ 540 private void addLapTime(long time) { 541 int size = mLapsAdapter.getCount(); 542 long curTime = time - mStartTime + mAccumulatedTime; 543 if (size == 0) { 544 // Always show the ending lap and a new one 545 mLapsAdapter.addLap(new Lap(curTime, curTime)); 546 mLapsAdapter.addLap(new Lap(0, curTime)); 547 mTime.setIntervalTime(curTime); 548 } else { 549 long lapTime = curTime - ((Lap) mLapsAdapter.getItem(1)).mTotalTime; 550 ((Lap)mLapsAdapter.getItem(0)).mLapTime = lapTime; 551 ((Lap)mLapsAdapter.getItem(0)).mTotalTime = curTime; 552 mLapsAdapter.addLap(new Lap(0, 0)); 553 mTime.setMarkerTime(lapTime); 554 // mTime.setIntervalTime(lapTime * 10); 555 } 556 mLapsAdapter.notifyDataSetChanged(); 557 // Start lap animation starting from the second lap 558 mTime.stopIntervalAnimation(); 559 if (!reachedMaxLaps()) { 560 mTime.startIntervalAnimation(); 561 } 562 } 563 564 private void updateCurrentLap(long totalTime) { 565 if (mLapsAdapter.getCount() > 0) { 566 Lap curLap = (Lap)mLapsAdapter.getItem(0); 567 curLap.mLapTime = totalTime - ((Lap)mLapsAdapter.getItem(1)).mTotalTime; 568 curLap.mTotalTime = totalTime; 569 mLapsAdapter.notifyDataSetChanged(); 570 } 571 } 572 573 private void showLaps() { 574 if (mLapsAdapter.getCount() > 0) { 575 mLapsList.setVisibility(View.VISIBLE); 576 } else { 577 mLapsList.setVisibility(View.INVISIBLE); 578 } 579 } 580 581 private void startUpdateThread() { 582 mTime.post(mTimeUpdateThread); 583 } 584 585 private void stopUpdateThread() { 586 mTime.removeCallbacks(mTimeUpdateThread); 587 } 588 589 Runnable mTimeUpdateThread = new Runnable() { 590 @Override 591 public void run() { 592 long curTime = Utils.getTimeNow(); 593 long totalTime = mAccumulatedTime + (curTime - mStartTime); 594 if (mTime != null) { 595 mTimeText.setTime(totalTime, true, true); 596 } 597 if (mLapsAdapter.getCount() > 0) { 598 updateCurrentLap(totalTime); 599 } 600 mTime.postDelayed(mTimeUpdateThread, 10); 601 } 602 }; 603 604 private void writeToSharedPref(SharedPreferences prefs) { 605 SharedPreferences.Editor editor = prefs.edit(); 606 editor.putLong (Stopwatches.PREF_START_TIME, mStartTime); 607 editor.putLong (Stopwatches.PREF_ACCUM_TIME, mAccumulatedTime); 608 editor.putInt (Stopwatches.PREF_STATE, mState); 609 if (mLapsAdapter != null) { 610 long [] laps = mLapsAdapter.getLapTimes(); 611 if (laps != null) { 612 editor.putInt (Stopwatches.PREF_LAP_NUM, laps.length); 613 for (int i = 0; i < laps.length; i++) { 614 String key = Stopwatches.PREF_LAP_TIME + Integer.toString(laps.length - i); 615 editor.putLong (key, laps[i]); 616 } 617 } 618 } 619 if (mState == Stopwatches.STOPWATCH_RUNNING) { 620 editor.putLong(Stopwatches.NOTIF_CLOCK_BASE, mStartTime-mAccumulatedTime); 621 editor.putLong(Stopwatches.NOTIF_CLOCK_ELAPSED, -1); 622 editor.putBoolean(Stopwatches.NOTIF_CLOCK_RUNNING, true); 623 } else if (mState == Stopwatches.STOPWATCH_STOPPED) { 624 editor.putLong(Stopwatches.NOTIF_CLOCK_ELAPSED, mAccumulatedTime); 625 editor.putLong(Stopwatches.NOTIF_CLOCK_BASE, -1); 626 editor.putBoolean(Stopwatches.NOTIF_CLOCK_RUNNING, false); 627 } else if (mState == Stopwatches.STOPWATCH_RESET) { 628 editor.remove(Stopwatches.NOTIF_CLOCK_BASE); 629 editor.remove(Stopwatches.NOTIF_CLOCK_RUNNING); 630 editor.remove(Stopwatches.NOTIF_CLOCK_ELAPSED); 631 } 632 editor.putBoolean(Stopwatches.PREF_UPDATE_CIRCLE, false); 633 editor.apply(); 634 } 635 636 private void readFromSharedPref(SharedPreferences prefs) { 637 mStartTime = prefs.getLong(Stopwatches.PREF_START_TIME, 0); 638 mAccumulatedTime = prefs.getLong(Stopwatches.PREF_ACCUM_TIME, 0); 639 mState = prefs.getInt(Stopwatches.PREF_STATE, Stopwatches.STOPWATCH_RESET); 640 int numLaps = prefs.getInt(Stopwatches.PREF_LAP_NUM, Stopwatches.STOPWATCH_RESET); 641 if (mLapsAdapter != null) { 642 long[] oldLaps = mLapsAdapter.getLapTimes(); 643 if (oldLaps == null || oldLaps.length < numLaps) { 644 long[] laps = new long[numLaps]; 645 long prevLapElapsedTime = 0; 646 for (int lap_i = 0; lap_i < numLaps; lap_i++) { 647 String key = Stopwatches.PREF_LAP_TIME + Integer.toString(lap_i + 1); 648 long lap = prefs.getLong(key, 0); 649 laps[numLaps - lap_i - 1] = lap - prevLapElapsedTime; 650 prevLapElapsedTime = lap; 651 } 652 mLapsAdapter.setLapTimes(laps); 653 } 654 } 655 if (prefs.getBoolean(Stopwatches.PREF_UPDATE_CIRCLE, true)) { 656 if (mState == Stopwatches.STOPWATCH_STOPPED) { 657 doStop(); 658 } else if (mState == Stopwatches.STOPWATCH_RUNNING) { 659 doStart(mStartTime); 660 } else if (mState == Stopwatches.STOPWATCH_RESET) { 661 doReset(); 662 } 663 } 664 } 665 666 private void clearSharedPref(SharedPreferences prefs) { 667 SharedPreferences.Editor editor = prefs.edit(); 668 editor.remove (Stopwatches.PREF_START_TIME); 669 editor.remove (Stopwatches.PREF_ACCUM_TIME); 670 editor.remove (Stopwatches.PREF_STATE); 671 int lapNum = prefs.getInt(Stopwatches.PREF_LAP_NUM, Stopwatches.STOPWATCH_RESET); 672 for (int i = 0; i < lapNum; i++) { 673 String key = Stopwatches.PREF_LAP_TIME + Integer.toString(i); 674 editor.remove(key); 675 } 676 editor.remove(Stopwatches.PREF_LAP_NUM); 677 editor.apply(); 678 } 679 680 public class ImageLabelAdapter extends ArrayAdapter<CharSequence> { 681 private final ArrayList<CharSequence> mStrings; 682 private final ArrayList<Drawable> mDrawables; 683 private final ArrayList<String> mPackageNames; 684 private final ArrayList<String> mClassNames; 685 private ImageLabelAdapter mShowAllAdapter; 686 687 public ImageLabelAdapter(Context context, int textViewResourceId, 688 ArrayList<CharSequence> strings, ArrayList<Drawable> drawables, 689 ArrayList<String> packageNames, ArrayList<String> classNames) { 690 super(context, textViewResourceId, strings); 691 mStrings = strings; 692 mDrawables = drawables; 693 mPackageNames = packageNames; 694 mClassNames = classNames; 695 } 696 697 // Use this constructor if showing a "see all" option, to pass in the adapter 698 // that will be needed to quickly show all the remaining options. 699 public ImageLabelAdapter(Context context, int textViewResourceId, 700 ArrayList<CharSequence> strings, ArrayList<Drawable> drawables, 701 ArrayList<String> packageNames, ArrayList<String> classNames, 702 ImageLabelAdapter showAllAdapter) { 703 super(context, textViewResourceId, strings); 704 mStrings = strings; 705 mDrawables = drawables; 706 mPackageNames = packageNames; 707 mClassNames = classNames; 708 mShowAllAdapter = showAllAdapter; 709 } 710 711 @Override 712 public View getView(int position, View convertView, ViewGroup parent) { 713 LayoutInflater li = getActivity().getLayoutInflater(); 714 View row = li.inflate(R.layout.popup_window_item, parent, false); 715 ((TextView) row.findViewById(R.id.title)).setText( 716 mStrings.get(position)); 717 ((ImageView) row.findViewById(R.id.icon)).setBackground( 718 mDrawables.get(position)); 719 return row; 720 } 721 722 public String getPackageName(int position) { 723 return mPackageNames.get(position); 724 } 725 726 public String getClassName(int position) { 727 return mClassNames.get(position); 728 } 729 730 public ImageLabelAdapter getShowAllAdapter() { 731 return mShowAllAdapter; 732 } 733 } 734 735 @Override 736 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { 737 if (prefs.equals(PreferenceManager.getDefaultSharedPreferences(getActivity()))) { 738 if (! (key.equals(Stopwatches.PREF_LAP_NUM) || 739 key.startsWith(Stopwatches.PREF_LAP_TIME))) { 740 readFromSharedPref(prefs); 741 if (prefs.getBoolean(Stopwatches.PREF_UPDATE_CIRCLE, true)) { 742 mTime.readFromSharedPref(prefs, "sw"); 743 } 744 } 745 } 746 } 747} 748