package net.rdrei.android.scdl2.ui; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.net.Uri; import android.os.Environment; import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.text.format.Formatter; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import net.rdrei.android.dirchooser.DirectoryChooserActivity; import net.rdrei.android.scdl2.ActivityStarter; import net.rdrei.android.scdl2.ApplicationPreferences; import net.rdrei.android.scdl2.ApplicationPreferences.StorageType; import net.rdrei.android.scdl2.Config; import net.rdrei.android.scdl2.DownloadPathValidator; import net.rdrei.android.scdl2.DownloadPathValidator.DownloadPathValidationException; import net.rdrei.android.scdl2.PackageHelper; import net.rdrei.android.scdl2.PreferenceManagerWrapper; import net.rdrei.android.scdl2.R; import roboguice.util.Ln; public class DownloadPreferencesDelegateImpl implements OnSharedPreferenceChangeListener, DownloadPreferencesDelegate { private static final String DOWNLOAD_DIRECTORY_NAME = "SoundCloud"; private static final String ANALYTICS_TAG = "DOWNLOAD_PREFERENCES"; private static final int REQUEST_DOWNLOAD_DIRECTORY_CHOOSER = 0; private ListPreference mTypePreference; private Preference mPathPreference; @Inject private ApplicationPreferences mAppPreferences; @Inject private SharedPreferences mSharedPreferences; @Inject private CustomPathChangeValidator mCustomPathValidator; @Inject private Context mContext; @Inject private PackageHelper mPackageHelper; private ActivityStarter mActivityStarter; @Inject private Tracker mTracker; private final PreferenceManagerWrapper mPreferenceManager; @Inject public DownloadPreferencesDelegateImpl(@Assisted final PreferenceManagerWrapper manager) { mPreferenceManager = manager; } /* * (non-Javadoc) * * @see net.rdrei.android.scdl2.ui.DownloadPreferencesDelegate#onCreate() */ @Override public void onCreate(final ActivityStarter activityStarter) { mTypePreference = (ListPreference) mPreferenceManager.findPreference( ApplicationPreferences.KEY_STORAGE_TYPE); mPathPreference = mPreferenceManager.findPreference( ApplicationPreferences.KEY_STORAGE_CUSTOM_PATH); mPathPreference.setOnPreferenceChangeListener(mCustomPathValidator); mPathPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(final Preference preference) { startDownloadDirectoryChooser(); return true; } }); setupAboutHandlers(); loadStorageTypeOptions(); mActivityStarter = activityStarter; } private void setupAboutHandlers() { final Uri uri = mPackageHelper.getMarketUri(); final Intent rateAppIntent = new Intent(Intent.ACTION_VIEW, uri); mPreferenceManager.findPreference(ApplicationPreferences.KEY_RATE_APP) .setIntent(rateAppIntent); final Intent aboutIntent = new Intent(mContext, AboutActivity.class); mPreferenceManager.findPreference(ApplicationPreferences.KEY_ABOUT_ME) .setIntent(aboutIntent); final Intent donateIntent = new Intent(mContext, BuyAdFreeActivity.class); final Preference donatePreference = mPreferenceManager.findPreference( ApplicationPreferences.KEY_DONATE); if (Config.Features.NEW_DONATE) { throw new IllegalStateException("New Donate isn't implemented yet, doh!"); } else { donatePreference.setIntent(donateIntent); donatePreference.setTitle(mContext.getString(R.string.remove_ads)); donatePreference.setEnabled(!mAppPreferences.isAdFree()); } } private void startDownloadDirectoryChooser() { final Intent chooseIntent = new Intent(mContext, DirectoryChooserActivity.class); chooseIntent.putExtra(DirectoryChooserActivity.EXTRA_NEW_DIR_NAME, DOWNLOAD_DIRECTORY_NAME); mActivityStarter.startActivityForResult(chooseIntent, REQUEST_DOWNLOAD_DIRECTORY_CHOOSER); } /* * (non-Javadoc) * * @see net.rdrei.android.scdl2.ui.DownloadPreferencesDelegate# * onSharedPreferenceChanged(android.content.SharedPreferences, * java.lang.String) */ @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { trackChange(sharedPreferences, key); updateStorageTypeSummary(); mPathPreference.setSummary(mAppPreferences.getCustomPath()); mPathPreference.setEnabled(mAppPreferences.getStorageType() == StorageType.CUSTOM); } private void updateStorageTypeSummary() { if (mAppPreferences.getStorageType() == StorageType.EXTERNAL) { mTypePreference.setSummary( String.format("%s (%s)", mAppPreferences.getStorageTypeDisplay(), mAppPreferences.getStorageDirectory())); } else { mTypePreference.setSummary(mAppPreferences.getStorageTypeDisplay()); } } /** * Let analytics know that there was a change. * * @param sharedPreferences * @param key */ private void trackChange(final SharedPreferences sharedPreferences, final String key) { String value = null; if (key == ApplicationPreferences.KEY_SSL_ENABLED) { value = String.valueOf(sharedPreferences.getBoolean(key, false)); } else if (key == ApplicationPreferences.KEY_STORAGE_TYPE || key == ApplicationPreferences.KEY_STORAGE_CUSTOM_PATH) { value = sharedPreferences.getString(key, "<undef>"); } if (value != null) { mTracker.send(new HitBuilders.EventBuilder() .setCategory(ANALYTICS_TAG) .setAction("CHANGE") .setLabel(key) .set("PREFERENCE", String.format("%s:%s", key, value)) .build() ); } } /* * (non-Javadoc) * * @see net.rdrei.android.scdl2.ui.DownloadPreferencesDelegate#onPause() */ @Override public void onPause() { mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); } /* * (non-Javadoc) * * @see net.rdrei.android.scdl2.ui.DownloadPreferencesDelegate#onResume() */ @Override public void onResume() { mSharedPreferences.registerOnSharedPreferenceChangeListener(this); // Trigger manually for initial display. onSharedPreferenceChanged(mSharedPreferences, null); } private void loadStorageTypeOptions() { mTypePreference.setEntries( new CharSequence[]{getExternalLabel(), getPhoneLabel(), mContext.getString( R.string.storage_custom_label)}); mTypePreference.setEntryValues( new String[]{StorageType.EXTERNAL.toString(), StorageType.LOCAL .toString(), StorageType.CUSTOM.toString(),}); updateStorageTypeSummary(); } private String getExternalLabel() { final long free = getFreeExternalStorage(); // This can be -1 or some other weird value on some Samsung crap devices. if (free >= 0) { final String freeStr = Formatter.formatShortFileSize(mContext, free); return String.format(mContext.getString(R.string.storage_sd_label), freeStr); } return mContext.getString(R.string.storage_sd_label_no_free); } private String getPhoneLabel() { final long free = getFreeInternalStorage(); if (free >= 0) { final String freeStr = Formatter.formatShortFileSize(mContext, free); return String.format(mContext.getString(R.string.storage_phone_label), freeStr); } return mContext.getString(R.string.storage_phone_label_no_free); } /** * Returns the free bytes on external storage. */ public static long getFreeExternalStorage() { return Environment.getExternalStorageDirectory().getUsableSpace(); } /** * Returns the free bytes on internal storage. */ public static long getFreeInternalStorage() { return Environment.getDataDirectory().getUsableSpace(); } @Override public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { Ln.i("onActivityResult: %d, %d, %s", requestCode, resultCode, data); if (requestCode == REQUEST_DOWNLOAD_DIRECTORY_CHOOSER && resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { final String directory = data.getStringExtra( DirectoryChooserActivity.RESULT_SELECTED_DIR); updateCustomPath(directory); Ln.i("New custom download path: %s", mAppPreferences.getCustomPath()); } } private void updateCustomPath(final String directory) { if (mCustomPathValidator.onPreferenceChange(mPathPreference, directory)) { final SharedPreferences.Editor editor = mPathPreference.getEditor(); if (editor != null) { editor.putString(ApplicationPreferences.KEY_STORAGE_CUSTOM_PATH, directory); editor.commit(); } } } private static class CustomPathChangeValidator implements Preference.OnPreferenceChangeListener { @Inject private DownloadPathValidator mValidator; @Override public boolean onPreferenceChange(final Preference preference, final Object newValue) { try { mValidator.validateCustomPathOrThrow((String) newValue); } catch (final DownloadPathValidationException e) { int errorMsgId; switch (e.getErrorCode()) { case INSECURE_PATH: errorMsgId = R.string.custom_path_error_insecure_path; break; case NOT_A_DIRECTORY: errorMsgId = R.string.custom_path_error_not_a_directory; break; case PERMISSION_DENIED: errorMsgId = R.string.custom_path_error_permission_denied; break; default: errorMsgId = R.string.custom_path_error_unknown; break; } showErrorDialog(preference.getContext(), errorMsgId); return false; } return true; } public void showErrorDialog(final Context context, final int errorMsgId) { final Builder builder = new AlertDialog.Builder(context); builder.setMessage(errorMsgId) .setTitle(R.string.custom_path_error_title) .setIcon(android.R.drawable.ic_dialog_alert) .show(); } } }