/*******************************************************************************
* Copyright (c) 2011 Adam Shanks (ChainsDD)
*
* 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.noshufou.android.su.preferences;
import com.noshufou.android.su.PinActivity;
import com.noshufou.android.su.R;
import com.noshufou.android.su.TagWriterActivity;
import com.noshufou.android.su.UpdaterActivity;
import com.noshufou.android.su.UpdaterFragment;
import com.noshufou.android.su.provider.PermissionsProvider.Logs;
import com.noshufou.android.su.service.ResultService;
import com.noshufou.android.su.util.BackupUtil;
import com.noshufou.android.su.util.Util;
import com.noshufou.android.su.widget.ChangeLog;
import com.noshufou.android.su.widget.NumberPickerDialog;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class PreferencesActivity extends PreferenceActivity implements OnClickListener,
OnSharedPreferenceChangeListener, OnPreferenceChangeListener {
private static final String TAG = "Su.PreferencesActivity";
private static final int REQUEST_ENABLE_PIN = 1;
private static final int REQUEST_DISABLE_PIN = 2;
private static final int REQUEST_CHANGE_PIN = 3;
private static final int REQUEST_WRITE_TAG = 4;
private static final int REQUEST_SECRET_CODE = 5;
SharedPreferences mPrefs = null;
private Preference mLogLimit = null;
private Preference mClearLog = null;
private Preference mToastLocation = null;
private Preference mApkVersion = null;
private Preference mBinVersion = null;
private CheckBoxPreference mOutdatedNotification = null;
private Preference mTimeoutPreference = null;
private CheckBoxPreference mPin = null;
private CheckBoxPreference mGhostMode = null;
private Preference mSecretCode = null;
private Context mContext;
private boolean mElite = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preferences);
addPreferencesFromResource(R.xml.preferences);
mContext = getApplicationContext();
// Set up the titlebar
((TextView)findViewById(R.id.title_text)).setText(R.string.pref_title);
((ImageButton)findViewById(R.id.home_button)).setOnClickListener(this);
PreferenceScreen prefScreen = getPreferenceScreen();
mPrefs = prefScreen.getSharedPreferences();
mElite = Util.elitePresent(mContext, false, 0);
if (!mElite) {
Log.i(TAG, "Elite not found, removing Elite preferences");
for (String s : Preferences.ELITE_PREFS) {
String[] bits = s.split(":");
if (bits[1].equals("all")) {
prefScreen.removePreference(findPreference(bits[0]));
} else {
((PreferenceCategory)findPreference(bits[0]))
.removePreference(findPreference(bits[1]));
}
}
} else {
mLogLimit = prefScreen.findPreference(Preferences.LOG_ENTRY_LIMIT);
mLogLimit.setSummary(getString(R.string.pref_log_entry_limit_summary,
mPrefs.getInt(Preferences.LOG_ENTRY_LIMIT, 200)));
mTimeoutPreference = prefScreen.findPreference(Preferences.TIMEOUT);
mTimeoutPreference.setSummary(getString(R.string.pref_timeout_summary,
mPrefs.getInt(Preferences.TIMEOUT, 0)));
mPin = (CheckBoxPreference) prefScreen.findPreference(Preferences.PIN);
mGhostMode = (CheckBoxPreference) prefScreen.findPreference(Preferences.GHOST_MODE);
mGhostMode.setOnPreferenceChangeListener(this);
mSecretCode = (Preference) prefScreen.findPreference(Preferences.SECRET_CODE);
mSecretCode.setSummary(getString(R.string.pref_secret_code_summary,
mPrefs.getString(Preferences.SECRET_CODE, "787378737")));
mSecretCode.setOnPreferenceChangeListener(this);
mToastLocation = prefScreen.findPreference(Preferences.TOAST_LOCATION);
mToastLocation.setEnabled(prefScreen.getSharedPreferences()
.getString(Preferences.NOTIFICATION_TYPE, "toast").equals("toast"));
// Remove NFC options if there's no NFC hardware
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
if (NfcAdapter.getDefaultAdapter(this) == null) {
prefScreen.removePreference(findPreference(Preferences.CATEGORY_NFC));
}
}
((PreferenceCategory)findPreference(Preferences.CATEGORY_INFO))
.removePreference(findPreference(Preferences.GET_ELITE));
}
mClearLog = prefScreen.findPreference(Preferences.CLEAR_LOG);
mApkVersion = prefScreen.findPreference(Preferences.VERSION);
mBinVersion = prefScreen.findPreference(Preferences.BIN_VERSION);
mOutdatedNotification = (CheckBoxPreference)
prefScreen.findPreference(Preferences.OUTDATED_NOTIFICATION);
mOutdatedNotification.setOnPreferenceChangeListener(this);
}
@Override
protected void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
new UpdateVersions().execute();
}
@Override
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.home_button:
goHome();
break;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
goHome();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void goHome() {
Util.goHome(this);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
String pref = preference.getKey();
if (pref.equals(Preferences.LOG_ENTRY_LIMIT)) {
new NumberPickerDialog(this,
mLogEntriesSet,
mPrefs.getInt(Preferences.LOG_ENTRY_LIMIT, 200),
0,
500,
R.string.pref_log_entry_limit_title).show();
} else if (pref.equals(Preferences.CLEAR_LOG)) {
new ClearLog().execute();
} else if (pref.equals(Preferences.BIN_VERSION)) {
final Intent intent = new Intent(this, UpdaterActivity.class);
startActivity(intent);
return true;
} else if (pref.equals(Preferences.PIN)) {
Intent intent = new Intent(this, PinActivity.class);
if (preferenceScreen.getSharedPreferences().getBoolean(Preferences.PIN, false)) {
intent.putExtra(PinActivity.EXTRA_MODE, PinActivity.MODE_NEW);
startActivityForResult(intent, REQUEST_ENABLE_PIN);
} else {
intent.putExtra(PinActivity.EXTRA_MODE, PinActivity.MODE_CHECK);
startActivityForResult(intent, REQUEST_DISABLE_PIN);
}
return true;
} else if (pref.equals(Preferences.CHANGE_PIN)) {
Intent intent = new Intent(this, PinActivity.class);
intent.putExtra(PinActivity.EXTRA_MODE, PinActivity.MODE_CHANGE);
startActivityForResult(intent, REQUEST_CHANGE_PIN);
} else if (pref.equals(Preferences.GHOST_MODE)) {
return true;
} else if (pref.equals(Preferences.SECRET_CODE)) {
Intent intent = new Intent(this, PinActivity.class);
intent.putExtra(PinActivity.EXTRA_MODE, PinActivity.MODE_SECRET_CODE);
startActivityForResult(intent, REQUEST_SECRET_CODE);
} else if (pref.equals(Preferences.TIMEOUT)) {
new NumberPickerDialog(this,
mTimeoutSet,
mPrefs.getInt(Preferences.TIMEOUT, 0),
0, 600,
R.string.pref_timeout_title).show();
} else if (pref.equals(Preferences.USE_ALLOW_TAG) ||
pref.equals(Preferences.WRITE_ALLOW_TAG)) {
if (!preferenceScreen.getSharedPreferences()
.getBoolean(Preferences.USE_ALLOW_TAG, false)) {
return false;
} else {
Intent intent = new Intent(this, PinActivity.class);
intent.putExtra(PinActivity.EXTRA_MODE, PinActivity.MODE_CHECK);
startActivityForResult(intent, REQUEST_WRITE_TAG);
return true;
}
} else if (pref.equals(Preferences.CHANGELOG)) {
ChangeLog cl = new ChangeLog(this);
cl.getFullLogDialog().show();
} else if (pref.equals(Preferences.GET_ELITE)) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id=com.noshufou.android.su.elite"));
startActivity(intent);
} else if (pref.equals(Preferences.BACKUP)) {
new BackupApps().execute();
} else if (pref.equals(Preferences.RESTORE)) {
new RestoreApps().execute();
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String pref = preference.getKey();
if (pref.equals(Preferences.GHOST_MODE)) {
final boolean ghostMode = (Boolean) newValue;
if (ghostMode) {
new AlertDialog.Builder(this).setTitle(R.string.pref_ghost_mode_title)
.setMessage(R.string.pref_ghost_mode_message)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mGhostMode.setChecked(true);
Util.toggleAppIcon(getApplicationContext(), !ghostMode);
new AlertDialog.Builder(PreferencesActivity.this)
.setTitle(R.string.pref_ghost_mode_title)
.setMessage(R.string.pref_ghost_mode_enabled_message)
.setPositiveButton(R.string.ok, null)
.create().show();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mGhostMode.setChecked(false);
}
}).create().show();
} else {
Util.toggleAppIcon(getApplicationContext(), !ghostMode);
return true;
}
return false;
} else if (pref.equals(Preferences.SECRET_CODE)) {
mSecretCode.setSummary(getString(R.string.pref_secret_code_summary,
((String)newValue)));
return true;
} else if (pref.equals(Preferences.OUTDATED_NOTIFICATION) && !((Boolean) newValue)) {
Log.d(TAG, "Cancel the notification");
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE))
.cancel(UpdaterFragment.NOTIFICATION_ID);
}
return true;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if (key.equals(Preferences.NOTIFICATION_TYPE) && mToastLocation != null) {
mToastLocation.setEnabled(sharedPreferences
.getString(Preferences.NOTIFICATION_TYPE, "toast").equals("toast"));
}
}
NumberPickerDialog.OnNumberSetListener mLogEntriesSet =
new NumberPickerDialog.OnNumberSetListener() {
@Override
public void onNumberSet(int number) {
mLogLimit.setSummary(getString(R.string.pref_log_entry_limit_summary, number));
mPrefs.edit().putInt(Preferences.LOG_ENTRY_LIMIT, number).commit();
final Intent intent = new Intent(mContext, ResultService.class);
intent.putExtra(ResultService.EXTRA_ACTION, ResultService.ACTION_RECYCLE);
startService(intent);
}
};
NumberPickerDialog.OnNumberSetListener mTimeoutSet =
new NumberPickerDialog.OnNumberSetListener() {
@Override
public void onNumberSet(int number) {
mTimeoutPreference.setSummary(getString(R.string.pref_timeout_summary, number));
mPrefs.edit().putInt(Preferences.TIMEOUT, number).commit();
}
};
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_CANCELED) {
switch (requestCode) {
case REQUEST_ENABLE_PIN:
mPin.setChecked(false);
break;
case REQUEST_DISABLE_PIN:
mPin.setChecked(true);
break;
}
return;
}
switch (requestCode) {
case REQUEST_ENABLE_PIN:
case REQUEST_CHANGE_PIN:
if (data.hasExtra(PinActivity.EXTRA_PIN)) {
CharSequence newPin = data.getCharSequenceExtra(PinActivity.EXTRA_PIN);
mPrefs.edit().putString("pin", newPin.toString()).commit();
mPin.setChecked(true);
}
break;
case REQUEST_DISABLE_PIN:
mPin.setChecked(false);
break;
case REQUEST_WRITE_TAG:
Intent intent = new Intent(this, TagWriterActivity.class);
intent.putExtra(TagWriterActivity.EXTRA_TAG, TagWriterActivity.TAG_ALLOW);
startActivity(intent);
break;
case REQUEST_SECRET_CODE:
CharSequence newSecretCode = data.getCharSequenceExtra(PinActivity.EXTRA_SECRET_CODE);
mPrefs.edit().putString(Preferences.SECRET_CODE, newSecretCode.toString()).commit();
mSecretCode.setSummary(getString(R.string.pref_secret_code_summary, newSecretCode));
break;
}
}
private class ClearLog extends AsyncTask<Void, Void, Integer> {
@Override
protected void onPreExecute() {
mClearLog.setTitle(R.string.pref_clearing_log_title);
mClearLog.setSummary(R.string.pref_clearing_log_summary);
mClearLog.setEnabled(false);
}
@Override
protected Integer doInBackground(Void... params) {
return getContentResolver().delete(Logs.CONTENT_URI, null, null);
}
@Override
protected void onPostExecute(Integer result) {
mClearLog.setTitle(R.string.pref_clear_log_title);
mClearLog.setSummary("");
mClearLog.setEnabled(true);
Toast.makeText(mContext,
getResources().getQuantityString(R.plurals.pref_logs_deleted, result, result),
Toast.LENGTH_SHORT).show();
}
}
private class UpdateVersions extends AsyncTask<Void, Integer, Integer> {
private String apkVersion;
private int apkVersionCode;
private String binVersion;
@Override
protected Integer doInBackground(Void... params) {
try {
PackageInfo pInfo = getPackageManager()
.getPackageInfo(getPackageName(), PackageManager.GET_META_DATA);
apkVersion = pInfo.versionName;
apkVersionCode = pInfo.versionCode;
} catch (NameNotFoundException e) {
Log.e(TAG, "Superuser is not installed?", e);
}
binVersion = Util.getSuVersion();
return 0;
}
@Override
protected void onPostExecute(Integer result) {
mApkVersion.setTitle(getString(R.string.pref_version_title, apkVersion, apkVersionCode));
mBinVersion.setTitle(getString(R.string.pref_bin_version_title, binVersion));
}
}
private class BackupApps extends AsyncTask<Void, Void, Boolean> {
@Override
protected void onPreExecute() {
((ProgressBar)findViewById(R.id.title_refresh_progress)).setVisibility(View.VISIBLE);
}
@Override
protected Boolean doInBackground(Void... params) {
return BackupUtil.makeBackup(PreferencesActivity.this);
}
@Override
protected void onPostExecute(Boolean result) {
((ProgressBar)findViewById(R.id.title_refresh_progress)).setVisibility(View.GONE);
if (result) {
Toast.makeText(getApplicationContext(),
getString(R.string.backup_complete), Toast.LENGTH_SHORT).show();
}
}
}
private class RestoreApps extends AsyncTask<Void, Void, Integer> {
@Override
protected void onPreExecute() {
((ProgressBar)findViewById(R.id.title_refresh_progress)).setVisibility(View.VISIBLE);
}
@Override
protected Integer doInBackground(Void... params) {
return BackupUtil.restoreBackup(PreferencesActivity.this);
}
@Override
protected void onPostExecute(Integer result) {
((ProgressBar)findViewById(R.id.title_refresh_progress)).setVisibility(View.GONE);
if (result > -1) {
String message = result > 0 ?
getResources().getQuantityString(R.plurals.restore_complete, result, result):
getString(R.string.restore_complete_prefs_only);
Toast.makeText(getApplicationContext(),
message,
Toast.LENGTH_SHORT).show();
Intent intent = getIntent();
finish();
startActivity(intent);
}
}
}
}