Java tutorial
package me.barrasso.android.volume.activities; import android.app.ActionBar; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.app.backup.BackupManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.media.AudioManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.preference.TwoStatePreference; import android.provider.Settings; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.LinearLayout; import android.widget.Switch; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; import com.readystatesoftware.systembartint.SystemBarTintManager; import com.squareup.otto.Subscribe; import com.mikepenz.aboutlibraries.Libs; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashSet; import java.util.List; import java.util.Set; import de.keyboardsurfer.android.widget.crouton.Style; import de.keyboardsurfer.android.widget.crouton.Crouton; import me.barrasso.android.volume.BuildConfig; import me.barrasso.android.volume.LogUtils; import me.barrasso.android.volume.R; import me.barrasso.android.volume.VolumeAccessibilityService; import me.barrasso.android.volume.media.VolumePanelInfo; import me.barrasso.android.volume.media.conditions.RingerNotificationLink; import me.barrasso.android.volume.popup.StatusBarVolumePanel; import me.barrasso.android.volume.popup.VolumePanel; import me.barrasso.android.volume.utils.Constants; import com.squareup.otto.MainThreadBus; import me.barrasso.android.volume.utils.DateUtils; import me.barrasso.android.volume.utils.Utils; import android.support.v7.widget.Toolbar; import static me.barrasso.android.volume.LogUtils.LOGD; import static me.barrasso.android.volume.LogUtils.LOGE; import static me.barrasso.android.volume.LogUtils.LOGI; public class ConfigurationActivity extends PreferenceActivity implements CompoundButton.OnCheckedChangeListener, SharedPreferences.OnSharedPreferenceChangeListener { public static final String TAG = LogUtils.makeLogTag(ConfigurationActivity.class); private SharedPreferences sp; private CompoundButton switchView; private Toolbar bar; @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); bar.setTitle(getTitle()); bar.inflateMenu(R.menu.toggle_switch); final MenuItem toggle = bar.getMenu().findItem(R.id.action_switch); if (null != toggle) { switchView = (CompoundButton) toggle.getActionView().findViewById(R.id.switch_view); if (null != switchView) { switchView.setChecked(VolumeAccessibilityService.isEnabled(this)); switchView.setOnCheckedChangeListener(this); } } if (isTaskRoot()) bar.setNavigationIcon(null); root.addView(bar, 0); bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } public void setToolbarTitle(String title) { bar.setTitle(title); } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupActionBar(this); MainThreadBus.get().register(this); ChangeLogDialog.show(this, true); // TRACK: activity view. if (NoyzeApp.GOOGLE_ANALYTICS) { Tracker t = ((NoyzeApp) getApplication()).getTracker(NoyzeApp.TrackerName.APP_TRACKER); t.setScreenName(getClass().getSimpleName()); t.send(new HitBuilders.AppViewBuilder().build()); } } @Override protected void onRestart() { LOGI(TAG, "onRestart()"); super.onRestart(); updateSwitchState(); } @Override protected void onStart() { LOGI(TAG, "onStart()"); super.onStart(); updateSwitchState(); } @Override protected void onResume() { LOGI(TAG, "onResume()"); super.onResume(); // Accountant.getInstance(this); updateSwitchState(); } @Override protected void onPause() { LOGI(TAG, "onPause()"); super.onPause(); if (null != sp) sp.unregisterOnSharedPreferenceChangeListener(this); sp = null; } @SuppressWarnings("unused") @Subscribe public void onVolumePanelChangeEvent(VolumeAccessibilityService.VolumePanelChangeEvent event) { LOGI(TAG, "onVolumePanelChangeEvent(" + event.getName() + ')'); boolean rControllerEnabled = Utils.isMediaControllerEnabled(this); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 && event.supportsMediaPlayback() && !isFinishing() && !rControllerEnabled) { NotificationFragment fragment = NotificationFragment.getInstance(false); if (null != fragment && null == getFragmentManager().findFragmentByTag(NotificationFragment.class.getSimpleName())) { fragment.show(getFragmentManager(), NotificationFragment.class.getSimpleName()); } } // TRACK: what theme is being used. if (NoyzeApp.GOOGLE_ANALYTICS) { Tracker t = ((NoyzeApp) getApplication()).getTracker(NoyzeApp.TrackerName.APP_TRACKER); t.send(new HitBuilders.EventBuilder().setCategory("Setting").setAction("Change") .setLabel(event.getName()).build()); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); try { MainThreadBus.get().unregister(this); } catch (Throwable t) { LOGE(TAG, "Error unregistering Otto bus.", t); } invokeFragmentManagerNoteStateNotSaved(); } @SuppressWarnings({ "rawtypes", "unchecked" }) private void invokeFragmentManagerNoteStateNotSaved() { // For post-Honeycomb devices if (Build.VERSION.SDK_INT < 11) { return; } try { Class<?> cls = getClass(); do { cls = cls.getSuperclass(); } while (!"Activity".equals(cls.getSimpleName())); Field fragmentMgrField = cls.getDeclaredField("mFragments"); fragmentMgrField.setAccessible(true); Object fragmentMgr = fragmentMgrField.get(this); cls = fragmentMgr.getClass(); Method noteStateNotSavedMethod = cls.getDeclaredMethod("noteStateNotSaved", new Class[] {}); noteStateNotSavedMethod.invoke(fragmentMgr); } catch (Exception ex) { LOGE(TAG, "Error on FM.noteStateNotSaved", ex); } } protected void updateSwitchState() { if (null == sp) { sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); sp.registerOnSharedPreferenceChangeListener(this); } if (null != switchView) { switchView.setOnCheckedChangeListener(null); switchView.setChecked(VolumeAccessibilityService.isEnabled(this)); switchView.setOnCheckedChangeListener(this); } } // Supported mainly to inform BackupManager of a change in settings. @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { LOGI(TAG, "onSharedPreferenceChanged(" + key + ')'); Context context = getApplicationContext(); if (null != context) { (new BackupManager(context)).dataChanged(); } if (Constants.PREF_VOLUME_PANEL.equals(key)) { // TRACK: what theme is being used. String panel = sharedPreferences.getString(key, StatusBarVolumePanel.TAG); VolumeAccessibilityService.VolumePanelChangeEvent event = new VolumeAccessibilityService.VolumePanelChangeEvent( panel, Utils.supportsMediaPlayback(panel)); onVolumePanelChangeEvent(event); } else if (Constants.PREF_REPORTING.equals(key)) { // TRACK: when the user opts out of being tracked. } } /** * Populate the activity with the top-level headers. */ @Override public void onBuildHeaders(List<Header> target) { super.onBuildHeaders(target); loadHeadersFromResource(R.xml.preference_headers, target); } @Override public void onHeaderClick(Header header, int position) { super.onHeaderClick(header, position); // NOTE: get IAP service ready BEFORE we open the setting. // Accountant.getInstance(this).connect(); LOGI(TAG, "onHeaderClick(" + header.id + ")"); switch ((int) header.id) { case R.id.header_about: launchAbout(findViewById((int) header.id)); break; case R.id.header_rate: Utils.launchMarketActivity(getApplicationContext()); break; case R.id.header_google_plus: launchGooglePlus(); break; } } private void launchGooglePlus() { Intent google = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.google_plus_url))); if (google.resolveActivity(getPackageManager()) != null) { startActivity(google); } else { Crouton.showText(this, R.string.url_error, Style.ALERT); } } private void launchAbout(View view) { Intent about = new Intent(getApplicationContext(), NoyzeLibActivity.class); about.putExtra(Libs.BUNDLE_FIELDS, Libs.toStringArray(R.string.class.getFields())); about.putExtra(Libs.BUNDLE_VERSION, true); about.putExtra(Libs.BUNDLE_LICENSE, true); about.putExtra(Libs.BUNDLE_TITLE, getString(R.string.about_settings)); about.putExtra(Libs.BUNDLE_THEME, R.style.AboutTheme); if (null == view) { startActivity(about); } else { ActivityOptionsCompat anim = ActivityOptionsCompat.makeSceneTransitionAnimation(this, view, "Google Plus"); ActivityCompat.startActivity(this, about, anim.toBundle()); } } private static final Set<String> VALID_FRAGMENTS = new HashSet<String>(); static { VALID_FRAGMENTS.add(InterfaceSettings.class.getName()); VALID_FRAGMENTS.add(MediaSettings.class.getName()); VALID_FRAGMENTS.add(LabSettings.class.getName()); VALID_FRAGMENTS.add(AdvancedSettings.class.getName()); } @Override public boolean isValidFragment(String name) { LOGD(TAG, "isValidFragment(" + name + ")"); return VALID_FRAGMENTS.contains(name); } public static class InterfaceSettings extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { String mVolumePanel = ""; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Accountant.getInstance(getActivity()); LOGI(getClass().getSimpleName(), "onCreate()"); getActivity().setTitle(getString(R.string.interface_settings)); addPreferencesFromResource(R.xml.interface_preferences); // Set whether the preference should be checked or not. mVolumePanel = VolumePanel.class.getSimpleName(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); prefs.registerOnSharedPreferenceChangeListener(this); updateFeatureList(null); } @Override public void onStart() { LOGI(getClass().getSimpleName(), "onStart()"); super.onStart(); } @Override public void onDestroy() { LOGI("InterfaceSettings", "onDestroy()"); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); prefs.unregisterOnSharedPreferenceChangeListener(this); super.onDestroy(); } protected void updateFeatureList(String name) { LOGI("InterfaceSettings", "updateFeatureList()"); if (TextUtils.isEmpty(name)) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); name = prefs.getString(mVolumePanel, name); } List<String> features = VolumePanelInfo.getSupportedFeatures(name); String[] allFeatures = VolumePanelInfo.getAllFeatures(); for (String feature : allFeatures) { Preference pref = findPreference(feature); pref.setEnabled(features.contains(feature)); } } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { LOGI("InterfaceSettings", "onSharedPreferenceChanged(" + key + ")"); if (mVolumePanel.equals(key)) { updateFeatureList(null); } } } public static class MediaSettings extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Accountant.getInstance(getActivity()); getActivity().setTitle(getString(R.string.media_settings)); addPreferencesFromResource(R.xml.media_preferences); // Check whether to show the notification-ringer volume link setting. AudioManager manager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); RingerNotificationLink linkChecker = new RingerNotificationLink(); boolean isNotifRingLinked = linkChecker.apply(manager); Preference link = findPreference("VolumePanel_linkNotifRinger"); link.setEnabled(!isNotifRingLinked); if (isNotifRingLinked) { PreferenceCategory category = (PreferenceCategory) findPreference("AudioMedia"); category.removePreference(link); } } @Override public void onStart() { LOGI(getClass().getSimpleName(), "onStart()"); super.onStart(); } } public static class LabSettings extends PreferenceFragment implements Preference.OnPreferenceChangeListener { TwoStatePreference notifPref; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Accountant.getInstance(getActivity()); getActivity().setTitle(getString(R.string.labs_title)); addPreferencesFromResource(R.xml.lab_preferences); // Set whether the preference should be checked or not. Preference pref = findPreference("MediaControllerService"); // For builds other than KitKat, hide RemoteController API. if (null != pref) pref.setOnPreferenceChangeListener(this); // Add out listeners and state change stuff. if (pref instanceof TwoStatePreference) { notifPref = (TwoStatePreference) pref; updateNotifPref(); } } protected void updateNotifPref() { if (null != notifPref) notifPref.setChecked(Utils.isMediaControllerEnabled(getActivity())); } @Override public void onStart() { LOGI(getClass().getSimpleName(), "onStart()"); super.onStart(); updateNotifPref(); } @Override public void onResume() { LOGI("LabSettings", "onResume()"); super.onStart(); updateNotifPref(); } @Override public boolean onPreferenceChange(Preference pref, Object newValue) { LOGD(TAG, "onPreferenceChange(" + newValue.toString() + ")"); boolean isNotif = ("MediaControllerService".equals(pref.getKey())); if (isNotif && !getActivity().isFinishing()) { NotificationFragment fragment = NotificationFragment .getInstance(Utils.isMediaControllerEnabled(getActivity())); if (null != fragment && null == getFragmentManager() .findFragmentByTag(NotificationFragment.class.getSimpleName())) { fragment.show(getFragmentManager(), NotificationFragment.class.getSimpleName()); } return false; } return true; } } public static class AdvancedSettings extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Accountant.getInstance(getActivity()); getActivity().setTitle(getString(R.string.advanced_title)); addPreferencesFromResource(R.xml.advanced_settings); // If available, place our build number in the version Preference. Preference version = findPreference("version"); if (null != version) version.setSummary(Utils.lastBuildTimestamp(getActivity())); } @Override public void onStart() { LOGI(getClass().getSimpleName(), "onStart()"); super.onStart(); } @Override public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference pref) { LOGI(TAG, "onPreferenceTreeClick(" + pref.getKey() + ")"); if (Constants.PREF_DEBUG_LOG.equals(pref.getKey())) { LogUtils.sendDebugLogAsync(getActivity()); // DEBUG // LogUtils.sendDebugLog(getActivity()); // DEBUG return true; } else if (Constants.PREF_CHANGELOG.equals(pref.getKey())) { ChangeLogDialog.show(getActivity(), false); } return super.onPreferenceTreeClick(screen, pref); } } public static void setupActionBar(Activity activity) { // Tint the status bar, if available. SystemBarTintManager tintManager = new SystemBarTintManager(activity); tintManager.setStatusBarTintEnabled(true); tintManager.setTintColor(activity.getResources().getColor(R.color.action_bar_dark)); ActionBar actionBar = activity.getActionBar(); if (null != actionBar) { actionBar.setIcon(DateUtils.AppIcon()); actionBar.setDisplayHomeAsUpEnabled(!activity.isTaskRoot()); actionBar.setDisplayShowTitleEnabled(true); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // R.menu.configure_overflow getMenuInflater().inflate(R.menu.toggle_switch, menu); // Get the action view used in your switch item final MenuItem toggle = menu.findItem(R.id.action_switch); if (null != toggle) { switchView = (CompoundButton) toggle.getActionView().findViewById(R.id.switch_view); if (null != switchView) { switchView.setChecked(VolumeAccessibilityService.isEnabled(this)); switchView.setOnCheckedChangeListener(this); } } return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); return true; } return super.onOptionsItemSelected(item); } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { LOGI(TAG, "Master switch: " + String.valueOf(isChecked)); boolean isRunning = VolumeAccessibilityService.isEnabled(this); switchView.setChecked(!isChecked); if (isFinishing()) return; AccessibilityFragment fragment = AccessibilityFragment.getInstance(isRunning); if (null != fragment && null == getFragmentManager().findFragmentByTag(AccessibilityFragment.class.getSimpleName())) { fragment.show(getFragmentManager(), AccessibilityFragment.class.getSimpleName()); } } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (!BuildConfig.DEBUG) { MenuItem sendLogsItem = menu.findItem(R.id.action_send_logs); if (sendLogsItem != null) { sendLogsItem.setVisible(false); } } return true; } @Override public void onDestroy() { LOGI(TAG, "onDestroy()"); Crouton.cancelAllCroutons(); try { MainThreadBus.get().unregister(this); } catch (Throwable t) { LOGE(TAG, "Unable to unregister from Otto.", t); } super.onDestroy(); } /** {@link android.app.Dialog} to inform the user about {@link android.accessibilityservice.AccessibilityService}. */ public static class AccessibilityFragment extends DialogFragment { static boolean isShowing = false; public static AccessibilityFragment getInstance(boolean isRunning) { if (isShowing) return null; AccessibilityFragment fragment = new AccessibilityFragment(); Bundle args = ((fragment.getArguments() == null) ? new Bundle() : fragment.getArguments()); args.putBoolean("active", isRunning); fragment.setArguments(args); isShowing = true; return fragment; } private boolean active; public AccessibilityFragment() { if (null != getArguments()) { active = getArguments().getBoolean("active"); } } @Override public void onStop() { super.onStop(); isShowing = false; } @Override public void dismiss() { super.dismiss(); isShowing = false; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); return builder.setTitle(R.string.accessibility_dialog_title) .setIcon(R.drawable.ic_settings_accessibility_black) .setMessage(((active) ? R.string.accessibility_dialog_description_on : R.string.accessibility_dialog_description)) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.take_me, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == Dialog.BUTTON_POSITIVE) { dismiss(); dialog.dismiss(); openAccessibility(); } } }).create(); } private void openAccessibility() { Intent accessibility = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); try { startActivity(accessibility); } catch (ActivityNotFoundException e) { LOGE(TAG, "Error opening Accessibility.", e); Crouton.showText(getActivity(), R.string.accessibility_error, Style.ALERT); } } } /** {@link android.app.Dialog} to inform the user about {@link android.service.notification.NotificationListenerService}. */ public static class NotificationFragment extends DialogFragment { static boolean isShowing = false; public static NotificationFragment getInstance(boolean isRunning) { if (isShowing) return null; NotificationFragment fragment = new NotificationFragment(); Bundle args = ((fragment.getArguments() == null) ? new Bundle() : fragment.getArguments()); args.putBoolean("active", isRunning); fragment.setArguments(args); isShowing = true; return fragment; } private boolean active; public NotificationFragment() { if (null != getArguments()) { active = getArguments().getBoolean("active"); } } @Override public void onStop() { super.onStop(); isShowing = false; } @Override public void dismiss() { super.dismiss(); isShowing = false; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); return builder.setTitle(R.string.notification_dialog_title) .setMessage(((active) ? R.string.notification_dialog_description_on : R.string.notification_dialog_description)) .setIcon(R.drawable.ic_audio_notification_pm).setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.take_me, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == Dialog.BUTTON_POSITIVE) { dismiss(); dialog.dismiss(); openNotification(); } } }).create(); } private void openNotification() { Intent notifications = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); try { startActivity(notifications); } catch (ActivityNotFoundException e) { LOGE(TAG, "Error opening NotificationListener.", e); Crouton.showText(getActivity(), R.string.accessibility_error, Style.ALERT); } } } }