Java tutorial
/**************************************************************************** * Copyright 2010 kraigs.android@gmail.com * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ****************************************************************************/ package com.iClone.AlarmChallenge; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.app.DialogFragment; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SwitchCompat; import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.CompoundButton; import android.widget.ListView; import android.widget.SeekBar; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; /** * This activity is used for editing alarm settings. Settings are broken * into two pieces: alarm information and actual settings. Every alarm will * have alarm information. Alarms will only have alarm settings if the user * has overridden the default settings for a given alarm. This dialog is used * to edit both the application default settings and individual alarm settings. * When editing the application default settings, no AlarmInfo object will * be present. When editing an alarm which hasn't yet had specific settings * set, AlarmSettings will contain the default settings. There is one required * EXTRA that must be supplied when starting this activity: EXTRAS_ALARM_ID, * which should contain a long representing the alarmId of the settings * being edited. AlarmSettings.DEFAULT_SETTINGS_ID can be used to edit the * default settings. */ public final class ActivityAlarmSettings extends AppCompatActivity implements TimePickerDialog.OnTimeChangedListener, TimePickerDialog.OnTimeSetListener { public static final String EXTRAS_ALARM_ID = "alarm_id"; private static final int MISSING_EXTRAS = -69; private static final int READ_EXTERNAL_STORAGE_PERMISSION_REQUEST = 0; private static final String SETTINGS_VIBRATE_KEY = "SETTINGS_VIBRATE_KEY"; private static final String SETTINGS_SNOOZE_KEY = "SETTINGS_SNOOZE_KEY"; private static final String SETTINGS_TIME_HOUR_OF_DAY_KEY = "SETTINGS_TIME_HOUR_OF_DAY_KEY"; private static final String SETTINGS_TIME_MINUTE_KEY = "SETTINGS_TIME_MINUTE_KEY"; private static final String SETTINGS_TIME_SECOND_KEY = "SETTINGS_TIME_SECOND_KEY"; private static final String SETTINGS_NAME_KEY = "SETTINGS_NAME_KEY"; private static final String SETTINGS_VOLUME_START_PERCENT_KEY = "SETTINGS_VOLUME_START_PERCENT_KEY"; private static final String SETTINGS_VOLUME_END_PERCENT_KEY = "SETTINGS_VOLUME_END_PERCENT_KEY"; private static final String SETTINGS_VOLUME_CHANGE_TIME_SEC_KEY = "SETTINGS_VOLUME_CHANGE_TIME_SEC_KEY"; private static final String SETTINGS_TONE_NAME_KEY = "SETTINGS_TONE_NAME_KEY"; private static final String SETTINGS_TONE_URI_KEY = "SETTINGS_TONE_URI_KEY"; private static final String SETTINGS_DAYS_OF_WEEK_KEY = "SETTINGS_DAYS_OF_WEEK_KEY"; private enum SettingType { TIME, NAME, DAYS_OF_WEEK, TONE, SNOOZE, VIBRATE, VOLUME_FADE, GAME_TYPE, GAME_DIFF, DELETE } public static final int NAME_PICKER = 1; public static final int DOW_PICKER = 2; public static final int TONE_PICKER = 3; public static final int SNOOZE_PICKER = 4; public static final int VOLUME_FADE_PICKER = 5; public static final int DELETE_CONFIRM = 6; public static final int EXPLAIN_READ_EXTERNAL_STORAGE = 7; public static final int PERMISSION_NOT_GRANTED = 8; private TimePickerDialog picker; private static long alarmId; private static AlarmClockServiceBinder service; private DbAccessor db; private AlarmInfo originalInfo; private static AlarmInfo info; private static AlarmSettings originalSettings; private static AlarmSettings settings; static SettingsAdapter settingsAdapter; private static ProgressDialog progressDialog; @Override protected void onCreate(Bundle savedInstanceState) { AppSettings.setTheme(getBaseContext(), ActivityAlarmSettings.this); super.onCreate(savedInstanceState); setContentView(R.layout.settings); setTitle(getString(R.string.settings)); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } alarmId = getIntent().getExtras().getLong(EXTRAS_ALARM_ID, MISSING_EXTRAS); if (alarmId == MISSING_EXTRAS) { throw new IllegalStateException("EXTRAS_ALARM_ID not supplied in intent."); } // Access to in-memory and persistent data structures. service = new AlarmClockServiceBinder(getApplicationContext()); db = new DbAccessor(getApplicationContext()); // Read the current settings from the database. Keep a copy of the // original values so that we can write new values only if they differ // from the originals. originalInfo = db.readAlarmInfo(alarmId); // Info will not be available for the default settings. if (originalInfo != null) { info = new AlarmInfo(originalInfo); if (savedInstanceState != null) { if (savedInstanceState.containsKey(SETTINGS_TIME_HOUR_OF_DAY_KEY) && savedInstanceState.containsKey(SETTINGS_TIME_MINUTE_KEY) && savedInstanceState.containsKey(SETTINGS_TIME_SECOND_KEY)) { final AlarmTime time = info.getTime(); info.setTime(new AlarmTime(savedInstanceState.getInt(SETTINGS_TIME_HOUR_OF_DAY_KEY), savedInstanceState.getInt(SETTINGS_TIME_MINUTE_KEY), savedInstanceState.getInt(SETTINGS_TIME_SECOND_KEY), time.getDaysOfWeek())); } if (savedInstanceState.containsKey(SETTINGS_NAME_KEY)) { info.setName(savedInstanceState.getString(SETTINGS_NAME_KEY)); } if (savedInstanceState.containsKey(SETTINGS_DAYS_OF_WEEK_KEY)) { info.setDaysOfWeek(new Week(savedInstanceState.getBooleanArray(SETTINGS_DAYS_OF_WEEK_KEY))); } } } originalSettings = db.readAlarmSettings(alarmId); settings = new AlarmSettings(originalSettings); if (savedInstanceState != null) { if (savedInstanceState.containsKey(SETTINGS_SNOOZE_KEY)) { settings.setSnoozeMinutes(savedInstanceState.getInt(SETTINGS_SNOOZE_KEY)); } if (savedInstanceState.containsKey(SETTINGS_VIBRATE_KEY)) { settings.setVibrate(savedInstanceState.getBoolean(SETTINGS_VIBRATE_KEY)); } if (savedInstanceState.containsKey(SETTINGS_VOLUME_START_PERCENT_KEY) && savedInstanceState.containsKey(SETTINGS_VOLUME_END_PERCENT_KEY) && savedInstanceState.containsKey(SETTINGS_VOLUME_CHANGE_TIME_SEC_KEY)) { settings.setVolumeStartPercent(savedInstanceState.getInt(SETTINGS_VOLUME_START_PERCENT_KEY)); settings.setVolumeEndPercent(savedInstanceState.getInt(SETTINGS_VOLUME_END_PERCENT_KEY)); settings.setVolumeChangeTimeSec(savedInstanceState.getInt(SETTINGS_VOLUME_CHANGE_TIME_SEC_KEY)); } if (savedInstanceState.containsKey(SETTINGS_TONE_URI_KEY) && savedInstanceState.containsKey(SETTINGS_TONE_NAME_KEY)) { settings.setTone((Uri) savedInstanceState.getParcelable(SETTINGS_TONE_URI_KEY), savedInstanceState.getString(SETTINGS_TONE_NAME_KEY)); } } // Setup the list of settings. Each setting is represented by a Setting // object. Create one here for each setting type. final ArrayList<Setting> settingsObjects = new ArrayList<>(SettingType.values().length); // Only display AlarmInfo if the user is editing an actual alarm (as // opposed to the default application settings). if (alarmId != AlarmSettings.DEFAULT_SETTINGS_ID) { // The alarm time. settingsObjects.add(new Setting() { @Override public String name() { return getString(R.string.time); } @Override public String value() { return info.getTime().localizedString(getApplicationContext()); } @Override public SettingType type() { return SettingType.TIME; } }); // A human-readable label for the alarm. settingsObjects.add(new Setting() { @Override public String name() { return getString(R.string.label); } @Override public String value() { return info.getName().equals("") ? getString(R.string.none) : info.getName(); } @Override public SettingType type() { return SettingType.NAME; } }); // Days of the week this alarm should repeat. settingsObjects.add(new Setting() { @Override public String name() { return getString(R.string.repeat); } @Override public String value() { return info.getTime().getDaysOfWeek().toString(getApplicationContext()); } @Override public SettingType type() { return SettingType.DAYS_OF_WEEK; } }); } // The notification tone used for this alarm. settingsObjects.add(new Setting() { @Override public String name() { return getString(R.string.tone); } @Override public String value() { String value = settings.getToneName(); // if (AppSettings.isDebugMode(getApplicationContext())) { // value += " " + settings.getTone().toString(); // } return value; } @Override public SettingType type() { return SettingType.TONE; } }); // The snooze duration for this alarm. settingsObjects.add(new Setting() { @Override public String name() { return getString(R.string.snooze_minutes); } @Override public String value() { return "" + settings.getSnoozeMinutes(); } @Override public SettingType type() { return SettingType.SNOOZE; } }); // The vibrator setting for this alarm. settingsObjects.add(new Setting() { @Override public String name() { return getString(R.string.vibrate); } @Override public String value() { return settings.getVibrate() ? getString(R.string.enabled) : getString(R.string.disabled); } @Override public SettingType type() { return SettingType.VIBRATE; } }); // How the volume should be controlled while this alarm is triggering. settingsObjects.add(new Setting() { @Override public String name() { return getString(R.string.alarm_fade); } @Override public String value() { return getString(R.string.fade_description, settings.getVolumeStartPercent(), settings.getVolumeEndPercent(), settings.getVolumeChangeTimeSec()); } @Override public SettingType type() { return SettingType.VOLUME_FADE; } }); final ListView settingsList = (ListView) findViewById(R.id.settings_list); settingsAdapter = new SettingsAdapter(getApplicationContext(), settingsObjects); settingsList.setAdapter(settingsAdapter); settingsList.setOnItemClickListener(new SettingsListClickListener()); } @Override public boolean onCreateOptionsMenu(Menu menu) { if (alarmId == AlarmSettings.DEFAULT_SETTINGS_ID) { return super.onCreateOptionsMenu(menu); } else { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.alarm_settings_menu, menu); return true; } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_delete_alarm: showDialogFragment(DELETE_CONFIRM); return true; case android.R.id.home: saveAlarmSettings(); finish(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onBackPressed() { super.onBackPressed(); saveAlarmSettings(); } @Override protected void onResume() { super.onResume(); service.bind(); TimePickerDialog tpd = (TimePickerDialog) getFragmentManager().findFragmentByTag("TimePickerDialog"); if (tpd != null) { picker = tpd; tpd.setOnTimeSetListener(this); tpd.setOnTimeChangedListener(this); } } @Override protected void onPause() { super.onPause(); service.unbind(); } @Override protected void onDestroy() { super.onDestroy(); db.closeConnections(); if (progressDialog != null) { progressDialog.dismiss(); } progressDialog = null; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == READ_EXTERNAL_STORAGE_PERMISSION_REQUEST) { if (permissions.length == 1 && permissions[0].equals(Manifest.permission.READ_EXTERNAL_STORAGE) && grantResults[0] == PackageManager.PERMISSION_GRANTED) { showProgressDialog(); showDialogFragment(TONE_PICKER); } else { showDialogFragment(PERMISSION_NOT_GRANTED); } } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(SETTINGS_VIBRATE_KEY, settings.getVibrate()); outState.putInt(SETTINGS_SNOOZE_KEY, settings.getSnoozeMinutes()); if (originalInfo != null && info != null) { final AlarmTime infoTime = info.getTime(); outState.putInt(SETTINGS_TIME_HOUR_OF_DAY_KEY, infoTime.calendar().get(Calendar.HOUR_OF_DAY)); outState.putInt(SETTINGS_TIME_MINUTE_KEY, infoTime.calendar().get(Calendar.MINUTE)); outState.putInt(SETTINGS_TIME_SECOND_KEY, infoTime.calendar().get(Calendar.SECOND)); outState.putString(SETTINGS_NAME_KEY, info.getName()); outState.putBooleanArray(SETTINGS_DAYS_OF_WEEK_KEY, info.getTime().getDaysOfWeek().bitmask()); } outState.putParcelable(SETTINGS_TONE_URI_KEY, settings.getTone()); outState.putString(SETTINGS_TONE_NAME_KEY, settings.getToneName()); outState.putInt(SETTINGS_VOLUME_START_PERCENT_KEY, settings.getVolumeStartPercent()); outState.putInt(SETTINGS_VOLUME_END_PERCENT_KEY, settings.getVolumeEndPercent()); outState.putInt(SETTINGS_VOLUME_CHANGE_TIME_SEC_KEY, settings.getVolumeChangeTimeSec()); } @Override public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute, int second) { final AlarmTime time = info.getTime(); info.setTime(new AlarmTime(hourOfDay, minute, second, time.getDaysOfWeek())); settingsAdapter.notifyDataSetChanged(); } @Override public void onTimeChanged(RadialPickerLayout view, int hourOfDay, int minute, int second) { final AlarmTime infoTime = info.getTime(); final AlarmTime time = new AlarmTime(hourOfDay, minute, second, infoTime.getDaysOfWeek()); picker.setTitle(time.timeUntilString(this)); } private void saveAlarmSettings() { // Write AlarmInfo if it changed. if (originalInfo != null && !originalInfo.equals(info)) { db.writeAlarmInfo(alarmId, info); // Explicitly enable the alarm if the user changed the time. // This will reschedule the alarm if it was already enabled. // It's also probably the right thing to do if the alarm wasn't // enabled. if (!originalInfo.getTime().equals(info.getTime())) { service.scheduleAlarm(alarmId); } } // Write AlarmSettings if they have changed. if (!originalSettings.equals(settings)) { db.writeAlarmSettings(alarmId, settings); } } public static void _requestReadExternalStoragePermission(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { ActivityCompat.requestPermissions(activity, new String[] { Manifest.permission.READ_EXTERNAL_STORAGE }, READ_EXTERNAL_STORAGE_PERMISSION_REQUEST); } } public void requestReadExternalStoragePermission() { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { showDialogFragment(EXPLAIN_READ_EXTERNAL_STORAGE); } else { _requestReadExternalStoragePermission(this); } } /** * This is a helper class for mapping SettingType to action. Each Setting * in the list view returns a unique SettingType. Trigger a dialog * based off of that SettingType. */ private final class SettingsListClickListener implements OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final SettingsAdapter adapter = (SettingsAdapter) parent.getAdapter(); SettingType type = adapter.getItem(position).type(); switch (type) { case TIME: final AlarmTime time = info.getTime(); Calendar c = time.calendar(); picker = TimePickerDialog.newInstance(ActivityAlarmSettings.this, ActivityAlarmSettings.this, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), DateFormat.is24HourFormat(ActivityAlarmSettings.this)); if (AppSettings.isThemeDark(ActivityAlarmSettings.this)) { picker.setThemeDark(true); } picker.setAccentColor(AppSettings.getTimePickerColor(ActivityAlarmSettings.this)); picker.vibrate(true); // if (AppSettings.isDebugMode(ActivityAlarmSettings.this)) { // picker.enableSeconds(true); // } else { // picker.enableSeconds(false); // } picker.setTitle(time.timeUntilString(ActivityAlarmSettings.this)); picker.show(getFragmentManager(), "TimePickerDialog"); break; case NAME: showDialogFragment(NAME_PICKER); break; case DAYS_OF_WEEK: showDialogFragment(DOW_PICKER); break; case TONE: if (ContextCompat.checkSelfPermission(ActivityAlarmSettings.this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { showProgressDialog(); showDialogFragment(TONE_PICKER); } else { requestReadExternalStoragePermission(); } break; } } } private void showProgressDialog() { progressDialog = ProgressDialog.show(ActivityAlarmSettings.this, getString(R.string.loading), getString(R.string.please_wait), true, true); } /** * A helper interface to encapsulate the data displayed in the list view of * this activity. Consists of a setting name, a setting value, and a type. * The type is used to trigger the appropriate action from the onClick * handler. */ private abstract class Setting { public abstract String name(); public abstract String value(); public abstract SettingType type(); } /** * This adapter populates the settings_items view with the data encapsulated * in the individual Setting objects. */ private final class SettingsAdapter extends ArrayAdapter<Setting> { List<Setting> settingsObjects; public SettingsAdapter(Context context, List<Setting> settingsObjects) { super(context, 0, settingsObjects); this.settingsObjects = settingsObjects; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; LayoutInflater inflater = getLayoutInflater(); if (settingsObjects.get(position).name().equalsIgnoreCase(getString(R.string.vibrate))) { convertView = inflater.inflate(R.layout.vibrate_settings_item, parent, false); } else { convertView = inflater.inflate(R.layout.settings_item, parent, false); } holder = new ViewHolder(convertView); convertView.setTag(holder); holder.populateFrom(settingsObjects.get(position)); return (convertView); } } private class ViewHolder { private View row; ViewHolder(View row) { this.row = row; } void populateFrom(Setting setting) { ((TextView) row.findViewById(R.id.setting_name)).setText(setting.name()); if (setting.name().equalsIgnoreCase(getString(R.string.vibrate))) { SwitchCompat vibrateSwitch = (SwitchCompat) row.findViewById(R.id.setting_vibrate_sc); if (settings.getVibrate()) { vibrateSwitch.setChecked(true); } else { vibrateSwitch.setChecked(false); } vibrateSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { settings.setVibrate(true); } else { settings.setVibrate(false); } } }); } else { ((TextView) row.findViewById(R.id.setting_value)).setText(setting.value()); } } } private void showDialogFragment(int id) { DialogFragment dialog = new ActivityDialogFragment().newInstance(id); dialog.show(getFragmentManager(), "ActivityDialogFragment"); } public static class ActivityDialogFragment extends DialogFragment { public ActivityDialogFragment newInstance(int id) { ActivityDialogFragment fragment = new ActivityDialogFragment(); Bundle args = new Bundle(); args.putInt("id", id); fragment.setArguments(args); return fragment; } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { switch (getArguments().getInt("id")) { case NAME_PICKER: final View nameView = View.inflate(getActivity(), R.layout.name_settings_dialog, null); final TextView label = (TextView) nameView.findViewById(R.id.name_label); label.setText(info.getName()); final AlertDialog.Builder nameBuilder = new AlertDialog.Builder(getActivity()); nameBuilder.setTitle(R.string.alarm_label); nameBuilder.setView(nameView); nameBuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { info.setName(label.getEditableText().toString()); settingsAdapter.notifyDataSetChanged(); dismiss(); } }); nameBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); return nameBuilder.create(); case DOW_PICKER: final AlertDialog.Builder dowBuilder = new AlertDialog.Builder(getActivity()); dowBuilder.setTitle(R.string.scheduled_days); dowBuilder.setMultiChoiceItems(info.getTime().getDaysOfWeek().names(getActivity()), info.getTime().getDaysOfWeek().bitmask(), new OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { if (isChecked) { info.getTime().getDaysOfWeek().addDay(Week.Day.values()[which]); } else { info.getTime().getDaysOfWeek().removeDay(Week.Day.values()[which]); } settingsAdapter.notifyDataSetChanged(); } }); dowBuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); return dowBuilder.create(); case TONE_PICKER: MediaPickerDialog mediaPicker = new MediaPickerDialog(getActivity()); mediaPicker.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { if (progressDialog != null) { progressDialog.dismiss(); progressDialog = null; } } }); mediaPicker.setPickListener(new MediaPickerDialog.OnMediaPickListener() { @Override public void onMediaPick(String name, Uri media) { if (name.length() == 0) { name = getString(R.string.unknown_name); } settings.setTone(media, name); settingsAdapter.notifyDataSetChanged(); } }); return mediaPicker; case SNOOZE_PICKER: // This currently imposes snooze times between 1 and 60 minutes, // which isn't really necessary, but I think the picker is easier // to use than a free-text field that you have to type numbers into. final CharSequence[] items = new CharSequence[60]; // Note the array index is one-off from the value (the value of 1 is // at index 0). for (int i = 1; i <= 60; ++i) { items[i - 1] = Integer.toString(i); } final AlertDialog.Builder snoozeBuilder = new AlertDialog.Builder(getActivity()); snoozeBuilder.setTitle(R.string.snooze_minutes); snoozeBuilder.setSingleChoiceItems(items, settings.getSnoozeMinutes() - 1, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { settings.setSnoozeMinutes(item + 1); settingsAdapter.notifyDataSetChanged(); dismiss(); } }); return snoozeBuilder.create(); case VOLUME_FADE_PICKER: final View fadeView = View.inflate(getActivity(), R.layout.fade_settings_dialog, null); final SeekBar seekBar = (SeekBar) fadeView.findViewById(R.id.volume_start_sb); seekBar.setMax(100); seekBar.setProgress(settings.getVolumeStartPercent()); final TextView textView = (TextView) fadeView.findViewById(R.id.volume_start_tv); textView.setText(getString(R.string.volume_start_label, settings.getVolumeStartPercent())); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { textView.setText(getString(R.string.volume_start_label, progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); final SeekBar endSeekBar = (SeekBar) fadeView.findViewById(R.id.volume_end_sb); endSeekBar.setMax(100); endSeekBar.setProgress(settings.getVolumeEndPercent()); final TextView endTextView = (TextView) fadeView.findViewById(R.id.volume_end_tv); endTextView.setText(getString(R.string.volume_end_label, settings.getVolumeEndPercent())); endSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { endTextView.setText(getString(R.string.volume_end_label, progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); final SeekBar durationSeekBar = (SeekBar) fadeView.findViewById(R.id.volume_duration_sb); durationSeekBar.setMax(300); durationSeekBar.setProgress(settings.getVolumeChangeTimeSec()); final TextView durationTextView = (TextView) fadeView.findViewById(R.id.volume_duration_tv); durationTextView .setText(getString(R.string.volume_duration_label, settings.getVolumeChangeTimeSec())); durationSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { durationTextView.setText(getString(R.string.volume_duration_label, progress)); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); final AlertDialog.Builder fadeBuilder = new AlertDialog.Builder(getActivity()); fadeBuilder.setTitle(R.string.alarm_fade); fadeBuilder.setView(fadeView); fadeBuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { settings.setVolumeStartPercent(seekBar.getProgress()); settings.setVolumeEndPercent(endSeekBar.getProgress()); settings.setVolumeChangeTimeSec(durationSeekBar.getProgress()); settingsAdapter.notifyDataSetChanged(); dismiss(); } }); fadeBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); return fadeBuilder.create(); case DELETE_CONFIRM: final AlertDialog.Builder deleteConfirmBuilder = new AlertDialog.Builder(getActivity()); deleteConfirmBuilder.setTitle(R.string.delete); deleteConfirmBuilder.setMessage(R.string.confirm_delete); deleteConfirmBuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { service.deleteAlarm(alarmId); dismiss(); getActivity().finish(); } }); deleteConfirmBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); return deleteConfirmBuilder.create(); case EXPLAIN_READ_EXTERNAL_STORAGE: final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.read_external_storage_title); builder.setMessage(R.string.read_external_storage_message); builder.setPositiveButton(R.string.grant, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); _requestReadExternalStoragePermission(getActivity()); } }); builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); return builder.create(); case PERMISSION_NOT_GRANTED: final AlertDialog.Builder permissionBuilder = new AlertDialog.Builder(getActivity()); permissionBuilder.setTitle(R.string.permission_not_granted_title); permissionBuilder.setMessage(R.string.permission_not_granted); permissionBuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); return permissionBuilder.create(); default: return super.onCreateDialog(savedInstanceState); } } } }