blob: 8ac1f27f9cd2c5098beb1842fc3d86dcfe485c2f [file] [log] [blame]
package com.android.deskclock.stopwatch;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListPopupWindow;
import android.widget.ListView;
import android.widget.PopupWindow.OnDismissListener;
import android.widget.TextView;
import com.android.deskclock.CircleButtonsLinearLayout;
import com.android.deskclock.CircleTimerView;
import com.android.deskclock.DeskClock;
import com.android.deskclock.DeskClockFragment;
import com.android.deskclock.Log;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
import com.android.deskclock.timer.CountingTimerView;
import java.util.ArrayList;
import java.util.List;
public class StopwatchFragment extends DeskClockFragment
implements OnSharedPreferenceChangeListener {
private static final String TAG = "StopwatchFragment";
int mState = Stopwatches.STOPWATCH_RESET;
// Stopwatch views that are accessed by the activity
private ImageButton mLeftButton;
private TextView mCenterButton;
private CircleTimerView mTime;
private CountingTimerView mTimeText;
private ListView mLapsList;
private ImageButton mShareButton;
private ListPopupWindow mSharePopup;
private WakeLock mWakeLock;
// Used for calculating the time from the start taking into account the pause times
long mStartTime = 0;
long mAccumulatedTime = 0;
// Lap information
class Lap {
Lap () {
mLapTime = 0;
mTotalTime = 0;
}
Lap (long time, long total) {
mLapTime = time;
mTotalTime = total;
}
public long mLapTime;
public long mTotalTime;
}
// Adapter for the ListView that shows the lap times.
class LapsListAdapter extends BaseAdapter {
ArrayList<Lap> mLaps = new ArrayList<Lap>();
private final LayoutInflater mInflater;
private final int mBackgroundColor;
private final String[] mFormats;
private final String[] mLapFormatSet;
// Size of this array must match the size of formats
private final long[] mThresholds = {
10 * DateUtils.MINUTE_IN_MILLIS, // < 10 minutes
DateUtils.HOUR_IN_MILLIS, // < 1 hour
10 * DateUtils.HOUR_IN_MILLIS, // < 10 hours
100 * DateUtils.HOUR_IN_MILLIS, // < 100 hours
1000 * DateUtils.HOUR_IN_MILLIS // < 1000 hours
};
private int mLapIndex = 0;
private int mTotalIndex = 0;
private String mLapFormat;
public LapsListAdapter(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBackgroundColor = getResources().getColor(R.color.blackish);
mFormats = context.getResources().getStringArray(R.array.stopwatch_format_set);
mLapFormatSet = context.getResources().getStringArray(R.array.sw_lap_number_set);
updateLapFormat();
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (mLaps.size() == 0 || position >= mLaps.size()) {
return null;
}
View lapInfo;
if (convertView != null) {
lapInfo = convertView;
} else {
lapInfo = mInflater.inflate(R.layout.lap_view, parent, false);
}
TextView count = (TextView)lapInfo.findViewById(R.id.lap_number);
TextView lapTime = (TextView)lapInfo.findViewById(R.id.lap_time);
TextView toalTime = (TextView)lapInfo.findViewById(R.id.lap_total);
lapTime.setText(Stopwatches.formatTimeText(mLaps.get(position).mLapTime,
mFormats[mLapIndex]));
toalTime.setText(Stopwatches.formatTimeText(mLaps.get(position).mTotalTime,
mFormats[mTotalIndex]));
count.setText(String.format(mLapFormat, mLaps.size() - position).toUpperCase());
lapInfo.setBackgroundColor(mBackgroundColor);
return lapInfo;
}
@Override
public int getCount() {
return mLaps.size();
}
@Override
public Object getItem(int position) {
if (mLaps.size() == 0 || position >= mLaps.size()) {
return null;
}
return mLaps.get(position);
}
private void updateLapFormat() {
// Note Stopwatches.MAX_LAPS < 100
mLapFormat = mLapFormatSet[mLaps.size() < 10 ? 0 : 1];
}
private void resetTimeFormats() {
mLapIndex = mTotalIndex = 0;
}
public boolean updateTimeFormats(Lap lap) {
boolean formatChanged = false;
while (mLapIndex + 1 < mThresholds.length && lap.mLapTime >= mThresholds[mLapIndex]) {
mLapIndex++;
formatChanged = true;
}
while (mTotalIndex + 1 < mThresholds.length &&
lap.mTotalTime >= mThresholds[mTotalIndex]) {
mTotalIndex++;
formatChanged = true;
}
return formatChanged;
}
public void addLap(Lap l) {
mLaps.add(0, l);
// for efficiency caller also calls notifyDataSetChanged()
}
public void clearLaps() {
mLaps.clear();
updateLapFormat();
resetTimeFormats();
notifyDataSetChanged();
}
// Helper function used to get the lap data to be stored in the activitys's bundle
public long [] getLapTimes() {
int size = mLaps.size();
if (size == 0) {
return null;
}
long [] laps = new long[size];
for (int i = 0; i < size; i ++) {
laps[i] = mLaps.get(i).mTotalTime;
}
return laps;
}
// Helper function to restore adapter's data from the activity's bundle
public void setLapTimes(long [] laps) {
if (laps == null || laps.length == 0) {
return;
}
int size = laps.length;
mLaps.clear();
for (int i = 0; i < size; i ++) {
mLaps.add(new Lap (laps[i], 0));
}
long totalTime = 0;
for (int i = size -1; i >= 0; i --) {
totalTime += laps[i];
mLaps.get(i).mTotalTime = totalTime;
updateTimeFormats(mLaps.get(i));
}
updateLapFormat();
notifyDataSetChanged();
}
}
// Keys for data stored in the activity's bundle
private static final String START_TIME_KEY = "start_time";
private static final String ACCUM_TIME_KEY = "accum_time";
private static final String STATE_KEY = "state";
private static final String LAPS_KEY = "laps";
LapsListAdapter mLapsAdapter;
public StopwatchFragment() {
}
private void rightButtonAction() {
long time = Utils.getTimeNow();
Context context = getActivity().getApplicationContext();
Intent intent = new Intent(context, StopwatchService.class);
intent.putExtra(Stopwatches.MESSAGE_TIME, time);
intent.putExtra(Stopwatches.SHOW_NOTIF, false);
switch (mState) {
case Stopwatches.STOPWATCH_RUNNING:
// do stop
long curTime = Utils.getTimeNow();
mAccumulatedTime += (curTime - mStartTime);
doStop();
intent.setAction(Stopwatches.STOP_STOPWATCH);
context.startService(intent);
releaseWakeLock();
break;
case Stopwatches.STOPWATCH_RESET:
case Stopwatches.STOPWATCH_STOPPED:
// do start
doStart(time);
intent.setAction(Stopwatches.START_STOPWATCH);
context.startService(intent);
acquireWakeLock();
break;
default:
Log.wtf("Illegal state " + mState
+ " while pressing the right stopwatch button");
break;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.stopwatch_fragment, container, false);
mLeftButton = (ImageButton)v.findViewById(R.id.stopwatch_left_button);
mLeftButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
long time = Utils.getTimeNow();
Context context = getActivity().getApplicationContext();
Intent intent = new Intent(context, StopwatchService.class);
intent.putExtra(Stopwatches.MESSAGE_TIME, time);
intent.putExtra(Stopwatches.SHOW_NOTIF, false);
switch (mState) {
case Stopwatches.STOPWATCH_RUNNING:
// Save lap time
addLapTime(time);
doLap();
intent.setAction(Stopwatches.LAP_STOPWATCH);
context.startService(intent);
break;
case Stopwatches.STOPWATCH_STOPPED:
// do reset
doReset();
intent.setAction(Stopwatches.RESET_STOPWATCH);
context.startService(intent);
releaseWakeLock();
break;
default:
Log.wtf("Illegal state " + mState
+ " while pressing the left stopwatch button");
break;
}
}
});
mCenterButton = (TextView)v.findViewById(R.id.stopwatch_stop);
mShareButton = (ImageButton)v.findViewById(R.id.stopwatch_share_button);
mShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showSharePopup();
}
});
// Timer text serves as a virtual start/stop button.
final CountingTimerView countingTimerView = (CountingTimerView)
v.findViewById(R.id.stopwatch_time_text);
countingTimerView.registerVirtualButtonAction(new Runnable() {
@Override
public void run() {
rightButtonAction();
}
});
countingTimerView.registerStopTextView(mCenterButton);
countingTimerView.setVirtualButtonEnabled(true);
mTime = (CircleTimerView)v.findViewById(R.id.stopwatch_time);
mTimeText = (CountingTimerView)v.findViewById(R.id.stopwatch_time_text);
mLapsList = (ListView)v.findViewById(R.id.laps_list);
mLapsList.setDividerHeight(0);
mLapsAdapter = new LapsListAdapter(getActivity());
if (mLapsList != null) {
mLapsList.setAdapter(mLapsAdapter);
}
CircleButtonsLinearLayout circleLayout =
(CircleButtonsLinearLayout)v.findViewById(R.id.stopwatch_circle);
circleLayout.setCircleTimerViewIds(R.id.stopwatch_time, R.id.stopwatch_left_button,
R.id.stopwatch_share_button, R.id.stopwatch_stop,
R.dimen.plusone_reset_button_padding, R.dimen.share_button_padding,
0, 0); /** No label for a stopwatch**/
return v;
}
@Override
public void onResume() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
prefs.registerOnSharedPreferenceChangeListener(this);
readFromSharedPref(prefs);
mTime.readFromSharedPref(prefs, "sw");
mTime.postInvalidate();
setButtons(mState);
mTimeText.setTime(mAccumulatedTime, true, true);
if (mState == Stopwatches.STOPWATCH_RUNNING) {
acquireWakeLock();
startUpdateThread();
} else if (mState == Stopwatches.STOPWATCH_STOPPED && mAccumulatedTime != 0) {
mTimeText.blinkTimeStr(true);
}
showLaps();
((DeskClock)getActivity()).registerPageChangedListener(this);
// View was hidden in onPause, make sure it is visible now.
View v = getView();
if (v != null) {
getView().setVisibility(View.VISIBLE);
}
super.onResume();
}
@Override
public void onPause() {
// This is called because the lock screen was activated, the window stay
// active under it and when we unlock the screen, we see the old time for
// a fraction of a second.
View v = getView();
if (v != null) {
getView().setVisibility(View.INVISIBLE);
}
if (mState == Stopwatches.STOPWATCH_RUNNING) {
stopUpdateThread();
}
// The stopwatch must keep running even if the user closes the app so save stopwatch state
// in shared prefs
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
prefs.unregisterOnSharedPreferenceChangeListener(this);
writeToSharedPref(prefs);
mTime.writeToSharedPref(prefs, "sw");
mTimeText.blinkTimeStr(false);
if (mSharePopup != null) {
mSharePopup.dismiss();
mSharePopup = null;
}
((DeskClock)getActivity()).unregisterPageChangedListener(this);
releaseWakeLock();
super.onPause();
}
@Override
public void onPageChanged(int page) {
if (page == DeskClock.STOPWATCH_TAB_INDEX && mState == Stopwatches.STOPWATCH_RUNNING) {
acquireWakeLock();
} else {
releaseWakeLock();
}
}
private void doStop() {
stopUpdateThread();
mTime.pauseIntervalAnimation();
mTimeText.setTime(mAccumulatedTime, true, true);
mTimeText.blinkTimeStr(true);
updateCurrentLap(mAccumulatedTime);
setButtons(Stopwatches.STOPWATCH_STOPPED);
mState = Stopwatches.STOPWATCH_STOPPED;
}
private void doStart(long time) {
mStartTime = time;
startUpdateThread();
mTimeText.blinkTimeStr(false);
if (mTime.isAnimating()) {
mTime.startIntervalAnimation();
}
setButtons(Stopwatches.STOPWATCH_RUNNING);
mState = Stopwatches.STOPWATCH_RUNNING;
}
private void doLap() {
showLaps();
setButtons(Stopwatches.STOPWATCH_RUNNING);
}
private void doReset() {
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(getActivity());
Utils.clearSwSharedPref(prefs);
mTime.clearSharedPref(prefs, "sw");
mAccumulatedTime = 0;
mLapsAdapter.clearLaps();
showLaps();
mTime.stopIntervalAnimation();
mTime.reset();
mTimeText.setTime(mAccumulatedTime, true, true);
mTimeText.blinkTimeStr(false);
setButtons(Stopwatches.STOPWATCH_RESET);
mState = Stopwatches.STOPWATCH_RESET;
}
private void showShareButton(boolean show) {
if (mShareButton != null) {
mShareButton.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
mShareButton.setEnabled(show);
}
}
private void showSharePopup() {
Intent intent = getShareIntent();
Activity parent = getActivity();
PackageManager packageManager = parent.getPackageManager();
// Get a list of sharable options.
List<ResolveInfo> shareOptions = packageManager
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (shareOptions.size() == 0) {
return;
}
ArrayList<CharSequence> shareOptionTitles = new ArrayList<CharSequence>();
ArrayList<Drawable> shareOptionIcons = new ArrayList<Drawable>();
ArrayList<CharSequence> shareOptionThreeTitles = new ArrayList<CharSequence>();
ArrayList<Drawable> shareOptionThreeIcons = new ArrayList<Drawable>();
ArrayList<String> shareOptionPackageNames = new ArrayList<String>();
ArrayList<String> shareOptionClassNames = new ArrayList<String>();
for (int option_i = 0; option_i < shareOptions.size(); option_i++) {
ResolveInfo option = shareOptions.get(option_i);
CharSequence label = option.loadLabel(packageManager);
Drawable icon = option.loadIcon(packageManager);
shareOptionTitles.add(label);
shareOptionIcons.add(icon);
if (shareOptions.size() > 4 && option_i < 3) {
shareOptionThreeTitles.add(label);
shareOptionThreeIcons.add(icon);
}
shareOptionPackageNames.add(option.activityInfo.packageName);
shareOptionClassNames.add(option.activityInfo.name);
}
if (shareOptionTitles.size() > 4) {
shareOptionThreeTitles.add(getResources().getString(R.string.see_all));
shareOptionThreeIcons.add(getResources().getDrawable(android.R.color.transparent));
}
if (mSharePopup != null) {
mSharePopup.dismiss();
mSharePopup = null;
}
mSharePopup = new ListPopupWindow(parent);
mSharePopup.setAnchorView(mShareButton);
mSharePopup.setModal(true);
// This adapter to show the rest will be used to quickly repopulate if "See all..." is hit.
ImageLabelAdapter showAllAdapter = new ImageLabelAdapter(parent,
R.layout.popup_window_item, shareOptionTitles, shareOptionIcons,
shareOptionPackageNames, shareOptionClassNames);
if (shareOptionTitles.size() > 4) {
mSharePopup.setAdapter(new ImageLabelAdapter(parent, R.layout.popup_window_item,
shareOptionThreeTitles, shareOptionThreeIcons, shareOptionPackageNames,
shareOptionClassNames, showAllAdapter));
} else {
mSharePopup.setAdapter(showAllAdapter);
}
mSharePopup.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CharSequence label = ((TextView) view.findViewById(R.id.title)).getText();
if (label.equals(getResources().getString(R.string.see_all))) {
mSharePopup.setAdapter(
((ImageLabelAdapter) parent.getAdapter()).getShowAllAdapter());
mSharePopup.show();
return;
}
Intent intent = getShareIntent();
ImageLabelAdapter adapter = (ImageLabelAdapter) parent.getAdapter();
String packageName = adapter.getPackageName(position);
String className = adapter.getClassName(position);
intent.setClassName(packageName, className);
startActivity(intent);
}
});
mSharePopup.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
mSharePopup = null;
}
});
mSharePopup.setWidth((int) getResources().getDimension(R.dimen.popup_window_width));
mSharePopup.show();
}
private Intent getShareIntent() {
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType("text/plain");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
intent.putExtra(Intent.EXTRA_SUBJECT,
Stopwatches.getShareTitle(getActivity().getApplicationContext()));
intent.putExtra(Intent.EXTRA_TEXT, Stopwatches.buildShareResults(
getActivity().getApplicationContext(), mTimeText.getTimeString(),
getLapShareTimes(mLapsAdapter.getLapTimes())));
return intent;
}
/** Turn laps as they would be saved in prefs into format for sharing. **/
private long[] getLapShareTimes(long[] input) {
if (input == null) {
return null;
}
int numLaps = input.length;
long[] output = new long[numLaps];
long prevLapElapsedTime = 0;
for (int lap_i = numLaps - 1; lap_i >= 0; lap_i--) {
long lap = input[lap_i];
Log.v("lap "+lap_i+": "+lap);
output[lap_i] = lap - prevLapElapsedTime;
prevLapElapsedTime = lap;
}
return output;
}
/***
* Update the buttons on the stopwatch according to the watch's state
*/
private void setButtons(int state) {
switch (state) {
case Stopwatches.STOPWATCH_RESET:
setButton(mLeftButton, R.string.sw_lap_button, R.drawable.ic_lap, false,
View.INVISIBLE);
setStartStopText(mCenterButton, R.string.sw_start_button);
showShareButton(false);
break;
case Stopwatches.STOPWATCH_RUNNING:
setButton(mLeftButton, R.string.sw_lap_button, R.drawable.ic_lap,
!reachedMaxLaps(), View.VISIBLE);
setStartStopText(mCenterButton, R.string.sw_stop_button);
showShareButton(false);
break;
case Stopwatches.STOPWATCH_STOPPED:
setButton(mLeftButton, R.string.sw_reset_button, R.drawable.ic_reset, true,
View.VISIBLE);
setStartStopText(mCenterButton, R.string.sw_start_button);
showShareButton(true);
break;
default:
break;
}
}
private boolean reachedMaxLaps() {
return mLapsAdapter.getCount() >= Stopwatches.MAX_LAPS;
}
/***
* Set a single button with the string and states provided.
* @param b - Button view to update
* @param text - Text in button
* @param enabled - enable/disables the button
* @param visibility - Show/hide the button
*/
private void setButton(
ImageButton b, int text, int drawableId, boolean enabled, int visibility) {
b.setContentDescription(getActivity().getResources().getString(text));
b.setImageResource(drawableId);
b.setVisibility(visibility);
b.setEnabled(enabled);
}
private void setStartStopText(TextView v, int text) {
String textStr = getActivity().getResources().getString(text);
v.setText(textStr);
v.setContentDescription(textStr);
}
/***
*
* @param time - in hundredths of a second
*/
private void addLapTime(long time) {
int size = mLapsAdapter.getCount();
long curTime = time - mStartTime + mAccumulatedTime;
if (size == 0) {
// Always show the ending lap and a new one
Lap firstLap = new Lap(curTime, curTime);
mLapsAdapter.addLap(firstLap);
mLapsAdapter.addLap(new Lap(0, curTime));
mTime.setIntervalTime(curTime);
mLapsAdapter.updateTimeFormats(firstLap);
} else {
long lapTime = curTime - ((Lap) mLapsAdapter.getItem(1)).mTotalTime;
((Lap)mLapsAdapter.getItem(0)).mLapTime = lapTime;
((Lap)mLapsAdapter.getItem(0)).mTotalTime = curTime;
mLapsAdapter.addLap(new Lap(0, 0));
mTime.setMarkerTime(lapTime);
mLapsAdapter.updateLapFormat();
// mTime.setIntervalTime(lapTime * 10);
}
mLapsAdapter.notifyDataSetChanged();
// Start lap animation starting from the second lap
mTime.stopIntervalAnimation();
if (!reachedMaxLaps()) {
mTime.startIntervalAnimation();
}
}
private void updateCurrentLap(long totalTime) {
if (mLapsAdapter.getCount() > 0) {
Lap curLap = (Lap)mLapsAdapter.getItem(0);
curLap.mLapTime = totalTime - ((Lap)mLapsAdapter.getItem(1)).mTotalTime;
curLap.mTotalTime = totalTime;
mLapsAdapter.notifyDataSetChanged();
}
}
private void showLaps() {
if (mLapsAdapter.getCount() > 0) {
mLapsList.setVisibility(View.VISIBLE);
} else {
mLapsList.setVisibility(View.INVISIBLE);
}
}
private void startUpdateThread() {
mTime.post(mTimeUpdateThread);
}
private void stopUpdateThread() {
mTime.removeCallbacks(mTimeUpdateThread);
}
Runnable mTimeUpdateThread = new Runnable() {
@Override
public void run() {
long curTime = Utils.getTimeNow();
long totalTime = mAccumulatedTime + (curTime - mStartTime);
if (mTime != null) {
mTimeText.setTime(totalTime, true, true);
}
if (mLapsAdapter.getCount() > 0) {
updateCurrentLap(totalTime);
}
mTime.postDelayed(mTimeUpdateThread, 10);
}
};
private void writeToSharedPref(SharedPreferences prefs) {
SharedPreferences.Editor editor = prefs.edit();
editor.putLong (Stopwatches.PREF_START_TIME, mStartTime);
editor.putLong (Stopwatches.PREF_ACCUM_TIME, mAccumulatedTime);
editor.putInt (Stopwatches.PREF_STATE, mState);
if (mLapsAdapter != null) {
long [] laps = mLapsAdapter.getLapTimes();
if (laps != null) {
editor.putInt (Stopwatches.PREF_LAP_NUM, laps.length);
for (int i = 0; i < laps.length; i++) {
String key = Stopwatches.PREF_LAP_TIME + Integer.toString(laps.length - i);
editor.putLong (key, laps[i]);
}
}
}
if (mState == Stopwatches.STOPWATCH_RUNNING) {
editor.putLong(Stopwatches.NOTIF_CLOCK_BASE, mStartTime-mAccumulatedTime);
editor.putLong(Stopwatches.NOTIF_CLOCK_ELAPSED, -1);
editor.putBoolean(Stopwatches.NOTIF_CLOCK_RUNNING, true);
} else if (mState == Stopwatches.STOPWATCH_STOPPED) {
editor.putLong(Stopwatches.NOTIF_CLOCK_ELAPSED, mAccumulatedTime);
editor.putLong(Stopwatches.NOTIF_CLOCK_BASE, -1);
editor.putBoolean(Stopwatches.NOTIF_CLOCK_RUNNING, false);
} else if (mState == Stopwatches.STOPWATCH_RESET) {
editor.remove(Stopwatches.NOTIF_CLOCK_BASE);
editor.remove(Stopwatches.NOTIF_CLOCK_RUNNING);
editor.remove(Stopwatches.NOTIF_CLOCK_ELAPSED);
}
editor.putBoolean(Stopwatches.PREF_UPDATE_CIRCLE, false);
editor.apply();
}
private void readFromSharedPref(SharedPreferences prefs) {
mStartTime = prefs.getLong(Stopwatches.PREF_START_TIME, 0);
mAccumulatedTime = prefs.getLong(Stopwatches.PREF_ACCUM_TIME, 0);
mState = prefs.getInt(Stopwatches.PREF_STATE, Stopwatches.STOPWATCH_RESET);
int numLaps = prefs.getInt(Stopwatches.PREF_LAP_NUM, Stopwatches.STOPWATCH_RESET);
if (mLapsAdapter != null) {
long[] oldLaps = mLapsAdapter.getLapTimes();
if (oldLaps == null || oldLaps.length < numLaps) {
long[] laps = new long[numLaps];
long prevLapElapsedTime = 0;
for (int lap_i = 0; lap_i < numLaps; lap_i++) {
String key = Stopwatches.PREF_LAP_TIME + Integer.toString(lap_i + 1);
long lap = prefs.getLong(key, 0);
laps[numLaps - lap_i - 1] = lap - prevLapElapsedTime;
prevLapElapsedTime = lap;
}
mLapsAdapter.setLapTimes(laps);
}
}
if (prefs.getBoolean(Stopwatches.PREF_UPDATE_CIRCLE, true)) {
if (mState == Stopwatches.STOPWATCH_STOPPED) {
doStop();
} else if (mState == Stopwatches.STOPWATCH_RUNNING) {
doStart(mStartTime);
} else if (mState == Stopwatches.STOPWATCH_RESET) {
doReset();
}
}
}
public class ImageLabelAdapter extends ArrayAdapter<CharSequence> {
private final ArrayList<CharSequence> mStrings;
private final ArrayList<Drawable> mDrawables;
private final ArrayList<String> mPackageNames;
private final ArrayList<String> mClassNames;
private ImageLabelAdapter mShowAllAdapter;
public ImageLabelAdapter(Context context, int textViewResourceId,
ArrayList<CharSequence> strings, ArrayList<Drawable> drawables,
ArrayList<String> packageNames, ArrayList<String> classNames) {
super(context, textViewResourceId, strings);
mStrings = strings;
mDrawables = drawables;
mPackageNames = packageNames;
mClassNames = classNames;
}
// Use this constructor if showing a "see all" option, to pass in the adapter
// that will be needed to quickly show all the remaining options.
public ImageLabelAdapter(Context context, int textViewResourceId,
ArrayList<CharSequence> strings, ArrayList<Drawable> drawables,
ArrayList<String> packageNames, ArrayList<String> classNames,
ImageLabelAdapter showAllAdapter) {
super(context, textViewResourceId, strings);
mStrings = strings;
mDrawables = drawables;
mPackageNames = packageNames;
mClassNames = classNames;
mShowAllAdapter = showAllAdapter;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater li = getActivity().getLayoutInflater();
View row = li.inflate(R.layout.popup_window_item, parent, false);
((TextView) row.findViewById(R.id.title)).setText(
mStrings.get(position));
((ImageView) row.findViewById(R.id.icon)).setBackground(
mDrawables.get(position));
return row;
}
public String getPackageName(int position) {
return mPackageNames.get(position);
}
public String getClassName(int position) {
return mClassNames.get(position);
}
public ImageLabelAdapter getShowAllAdapter() {
return mShowAllAdapter;
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (prefs.equals(PreferenceManager.getDefaultSharedPreferences(getActivity()))) {
if (! (key.equals(Stopwatches.PREF_LAP_NUM) ||
key.startsWith(Stopwatches.PREF_LAP_TIME))) {
readFromSharedPref(prefs);
if (prefs.getBoolean(Stopwatches.PREF_UPDATE_CIRCLE, true)) {
mTime.readFromSharedPref(prefs, "sw");
}
}
}
}
// Used to keeps screen on when stopwatch is running.
private void acquireWakeLock() {
if (mWakeLock == null) {
final PowerManager pm =
(PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG);
mWakeLock.setReferenceCounted(false);
}
mWakeLock.acquire();
}
private void releaseWakeLock() {
if (mWakeLock != null && mWakeLock.isHeld()) {
mWakeLock.release();
}
}
}