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