package de.robv.android.xposed.mods.appsettings.settings; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.Color; import android.graphics.PorterDuff.Mode; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageView; import android.widget.ScrollView; import android.widget.Spinner; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; import de.robv.android.xposed.mods.appsettings.Common; import de.robv.android.xposed.mods.appsettings.R; @SuppressLint("WorldReadableFiles") public class ApplicationSettings extends Activity { private Switch swtActive; private String pkgName; private SharedPreferences prefs; private Set<String> settingKeys; private Map<String, Object> initialSettings; private Set<String> disabledPermissions; private boolean allowRevoking; private Intent parentIntent; private LocaleList localeList; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); swtActive = new Switch(this); getActionBar().setCustomView(swtActive); getActionBar().setDisplayShowCustomEnabled(true); setContentView(R.layout.app_settings); Intent i = getIntent(); parentIntent = i; prefs = getSharedPreferences(Common.PREFS, Context.MODE_WORLD_READABLE); ApplicationInfo app; try { app = getPackageManager().getApplicationInfo(i.getStringExtra("package"), 0); pkgName = app.packageName; } catch (NameNotFoundException e) { // Close the dialog gracefully, package might have been uninstalled finish(); return; } // Display app info ((TextView) findViewById(R.id.app_label)).setText(app.loadLabel(getPackageManager())); ((TextView) findViewById(R.id.package_name)).setText(app.packageName); ((ImageView) findViewById(R.id.app_icon)).setImageDrawable(app.loadIcon(getPackageManager())); // Update switch of active/inactive tweaks if (prefs.getBoolean(pkgName + Common.PREF_ACTIVE, false)) { swtActive.setChecked(true); findViewById(R.id.viewTweaks).setVisibility(View.VISIBLE); } else { swtActive.setChecked(false); findViewById(R.id.viewTweaks).setVisibility(View.GONE); } // Toggle the visibility of the lower panel when changed swtActive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { findViewById(R.id.viewTweaks).setVisibility(isChecked ? View.VISIBLE : View.GONE); } }); // Update DPI field if (prefs.getBoolean(pkgName + Common.PREF_ACTIVE, false)) { ((EditText) findViewById(R.id.txtDPI)).setText(String.valueOf( prefs.getInt(pkgName + Common.PREF_DPI, 0))); } else { ((EditText) findViewById(R.id.txtDPI)).setText("0"); } // Update Font Scaling field if (prefs.getBoolean(pkgName + Common.PREF_ACTIVE, false)) { ((EditText) findViewById(R.id.txtFontScale)).setText(String.valueOf(prefs.getInt(pkgName + Common.PREF_FONT_SCALE, 100))); } else { ((EditText) findViewById(R.id.txtFontScale)).setText("100"); } // Load and render current screen setting + possible options int screen = prefs.getInt(pkgName + Common.PREF_SCREEN, 0); if (screen < 0 || screen >= Common.swdp.length) screen = 0; final int selectedScreen = screen; Spinner spnScreen = (Spinner) findViewById(R.id.spnScreen); List<String> lstScreens = new ArrayList<String>(Common.swdp.length); lstScreens.add(getString(R.string.settings_default)); for (int j = 1; j < Common.swdp.length; j++) lstScreens.add(String.format("%dx%d", Common.wdp[j], Common.hdp[j])); ArrayAdapter<String> screenAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, lstScreens); screenAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnScreen.setAdapter(screenAdapter); spnScreen.setSelection(selectedScreen); // Update Tablet field ((CheckBox) findViewById(R.id.chkXlarge)).setChecked(prefs.getBoolean(pkgName + Common.PREF_XLARGE, false)); // Update Res On Widgets field ((CheckBox) findViewById(R.id.chkResOnWidgets)).setChecked(prefs.getBoolean(pkgName + Common.PREF_RES_ON_WIDGETS, false)); // Update Language and list of possibilities localeList = new LocaleList(getString(R.string.settings_default)); final Spinner spnLanguage = (Spinner) findViewById(R.id.spnLocale); ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, localeList.getDescriptionList()); dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnLanguage.setAdapter(dataAdapter); int selectedLocalePos = localeList.getLocalePos(prefs.getString(pkgName + Common.PREF_LOCALE, null)); spnLanguage.setSelection(selectedLocalePos); spnLanguage.setLongClickable(true); spnLanguage.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View arg0) { int selPos = spnLanguage.getSelectedItemPosition(); if (selPos > 0) Toast.makeText(getApplicationContext(), localeList.getLocale(selPos), Toast.LENGTH_SHORT).show(); return true; } }); // Helper to list all apk folders under /res ((Button) findViewById(R.id.btnListRes)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AlertDialog.Builder builder = new AlertDialog.Builder(ApplicationSettings.this); ScrollView scrollPane = new ScrollView(ApplicationSettings.this); TextView txtPane = new TextView(ApplicationSettings.this); StringBuilder contents = new StringBuilder(); JarFile jar = null; TreeSet<String> resEntries = new TreeSet<String>(); Matcher m = Pattern.compile("res/(.+)/[^/]+").matcher(""); try { ApplicationInfo app = getPackageManager().getApplicationInfo(pkgName, 0); jar = new JarFile(app.publicSourceDir); Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); m.reset(entry.getName()); if (m.matches()) resEntries.add(m.group(1)); } if (resEntries.size() == 0) resEntries.add(getString(R.string.res_noentries)); jar.close(); for (String dir : resEntries) { contents.append('\n'); contents.append(dir); } contents.deleteCharAt(0); } catch (Exception e) { contents.append(getString(R.string.res_failedtoload)); if (jar != null) { try { jar.close(); } catch (Exception ex) { } } } txtPane.setText(contents); scrollPane.addView(txtPane); builder.setView(scrollPane); builder.setTitle(R.string.res_title); builder.show(); } }); // Setup fullscreen settings { int fullscreen; try { fullscreen = prefs.getInt(pkgName + Common.PREF_FULLSCREEN, Common.FULLSCREEN_DEFAULT); } catch (ClassCastException ex) { // Legacy boolean setting fullscreen = prefs.getBoolean(pkgName + Common.PREF_FULLSCREEN, false) ? Common.FULLSCREEN_FORCE : Common.FULLSCREEN_DEFAULT; } final int fullscreenSelection = fullscreen; Spinner spnFullscreen = (Spinner) findViewById(R.id.spnFullscreen); // Note: the order of these items must match the Common.FULLSCREEN_... constants String[] fullscreenArray; if (Build.VERSION.SDK_INT >= 19) { fullscreenArray = new String[] { getString(R.string.settings_default), getString(R.string.settings_force), getString(R.string.settings_prevent), getString(R.string.settings_immersive) }; } else { fullscreenArray = new String[] { getString(R.string.settings_default), getString(R.string.settings_force), getString(R.string.settings_prevent) }; } List<String> lstFullscreen = Arrays.asList(fullscreenArray); ArrayAdapter<String> fullscreenAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, lstFullscreen); fullscreenAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnFullscreen.setAdapter(fullscreenAdapter); spnFullscreen.setSelection(fullscreenSelection); } // Update No Title field ((CheckBox) findViewById(R.id.chkNoTitle)).setChecked(prefs.getBoolean(pkgName + Common.PREF_NO_TITLE, false)); // Update Allow On Lockscreen field ((CheckBox) findViewById(R.id.chkAllowOnLockscreen)).setChecked(prefs.getBoolean(pkgName + Common.PREF_ALLOW_ON_LOCKSCREEN, false)); // Update Screen On field ((CheckBox) findViewById(R.id.chkScreenOn)).setChecked(prefs.getBoolean(pkgName + Common.PREF_SCREEN_ON, false)); // Load and render current screen setting + possible options int orientation = prefs.getInt(pkgName + Common.PREF_ORIENTATION, 0); if (orientation < 0 || orientation >= Common.orientationCodes.length) orientation = 0; final int selectedOrientation = orientation; Spinner spnOrientation = (Spinner) findViewById(R.id.spnOrientation); List<String> lstOrientations = new ArrayList<String>(Common.orientationLabels.length); for (int j = 0; j < Common.orientationLabels.length; j++) lstOrientations.add(getString(Common.orientationLabels[j])); ArrayAdapter<String> orientationAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, lstOrientations); orientationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnOrientation.setAdapter(orientationAdapter); spnOrientation.setSelection(selectedOrientation); // Setting for making the app resident in memory ((CheckBox) findViewById(R.id.chkResident)).setChecked(prefs.getBoolean(pkgName + Common.PREF_RESIDENT, false)); // Setting for disabling fullscreen IME ((CheckBox) findViewById(R.id.chkNoFullscreenIME)).setChecked(prefs.getBoolean(pkgName + Common.PREF_NO_FULLSCREEN_IME, false)); // Update No Big Notifications field if (Build.VERSION.SDK_INT >= 16) { ((CheckBox) findViewById(R.id.chkNoBigNotifications)).setChecked(prefs.getBoolean(pkgName + Common.PREF_NO_BIG_NOTIFICATIONS, false)); } else { findViewById(R.id.chkNoBigNotifications).setVisibility(View.GONE); } // Setup Ongoing Notifications settings { int ongoingNotifs = prefs.getInt(pkgName + Common.PREF_ONGOING_NOTIF, Common.ONGOING_NOTIF_DEFAULT); Spinner spnOngoingNotif = (Spinner) findViewById(R.id.spnOngoingNotifications); // Note: the order of these items must match the Common.ONGOING_NOTIF_... constants String[] ongoingNotifArray = new String[] { getString(R.string.settings_default), getString(R.string.settings_force), getString(R.string.settings_prevent) }; List<String> lstOngoingNotif = Arrays.asList(ongoingNotifArray); ArrayAdapter<String> ongoingNotifAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, lstOngoingNotif); ongoingNotifAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnOngoingNotif.setAdapter(ongoingNotifAdapter); spnOngoingNotif.setSelection(ongoingNotifs); } // Update Insistent Notifications field ((CheckBox) findViewById(R.id.chkInsistentNotifications)).setChecked(prefs.getBoolean(pkgName + Common.PREF_INSISTENT_NOTIF, false)); // Load and render notifications priority if (Build.VERSION.SDK_INT >= 16) { int notifPriority = prefs.getInt(pkgName + Common.PREF_NOTIF_PRIORITY, 0); if (notifPriority < 0 || notifPriority >= Common.notifPriCodes.length) notifPriority = 0; final int selectedNotifPriority = notifPriority; Spinner spnNotifPri = (Spinner) findViewById(R.id.spnNotifPriority); List<String> lstNotifPriorities = new ArrayList<String>(Common.notifPriLabels.length); for (int j = 0; j < Common.notifPriLabels.length; j++) lstNotifPriorities.add(getString(Common.notifPriLabels[j])); ArrayAdapter<String> notifPriAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, lstNotifPriorities); notifPriAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnNotifPri.setAdapter(notifPriAdapter); spnNotifPri.setSelection(selectedNotifPriority); } else { findViewById(R.id.viewNotifPriority).setVisibility(View.GONE); } // Update Mute field ((CheckBox) findViewById(R.id.chkMute)).setChecked(prefs.getBoolean(pkgName + Common.PREF_MUTE, false)); // Update Legacy Menu field ((CheckBox) findViewById(R.id.chkLegacyMenu)).setChecked(prefs.getBoolean(pkgName + Common.PREF_LEGACY_MENU, false)); // Setting for permissions revoking allowRevoking = prefs.getBoolean(pkgName + Common.PREF_REVOKEPERMS, false); disabledPermissions = prefs.getStringSet(pkgName + Common.PREF_REVOKELIST, new HashSet<String>()); // Setup recents mode options final int selectedRecentsMode = prefs.getInt(pkgName + Common.PREF_RECENTS_MODE, Common.PREF_RECENTS_DEFAULT); // Note: the order of these items must match the Common.RECENTS_... constants String[] recentsModeArray = new String[] { getString(R.string.settings_default), getString(R.string.settings_force), getString(R.string.settings_prevent) }; Spinner spnRecentsMode = (Spinner) findViewById(R.id.spnRecentsMode); List<String> lstRecentsMode = Arrays.asList(recentsModeArray); ArrayAdapter<String> recentsModeAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, lstRecentsMode); recentsModeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnRecentsMode.setAdapter(recentsModeAdapter); spnRecentsMode.setSelection(selectedRecentsMode); Button btnPermissions = (Button) findViewById(R.id.btnPermissions); btnPermissions.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // set up permissions editor try { final PermissionSettings permsDlg = new PermissionSettings(ApplicationSettings.this, pkgName, allowRevoking, disabledPermissions); permsDlg.setOnOkListener(new PermissionSettings.OnDismissListener() { @Override public void onDismiss(PermissionSettings obj) { allowRevoking = permsDlg.getRevokeActive(); disabledPermissions.clear(); disabledPermissions.addAll(permsDlg.getDisabledPermissions()); } }); permsDlg.display(); } catch (NameNotFoundException e) { } } }); settingKeys = getSettingKeys(); initialSettings = getSettings(); } private Set<String> getSettingKeys() { HashSet<String> settingKeys = new HashSet<String>(); settingKeys.add(pkgName + Common.PREF_ACTIVE); settingKeys.add(pkgName + Common.PREF_DPI); settingKeys.add(pkgName + Common.PREF_FONT_SCALE); settingKeys.add(pkgName + Common.PREF_SCREEN); settingKeys.add(pkgName + Common.PREF_XLARGE); settingKeys.add(pkgName + Common.PREF_RES_ON_WIDGETS); settingKeys.add(pkgName + Common.PREF_LOCALE); settingKeys.add(pkgName + Common.PREF_FULLSCREEN); settingKeys.add(pkgName + Common.PREF_NO_TITLE); settingKeys.add(pkgName + Common.PREF_ALLOW_ON_LOCKSCREEN); settingKeys.add(pkgName + Common.PREF_SCREEN_ON); settingKeys.add(pkgName + Common.PREF_ORIENTATION); settingKeys.add(pkgName + Common.PREF_RESIDENT); settingKeys.add(pkgName + Common.PREF_NO_FULLSCREEN_IME); settingKeys.add(pkgName + Common.PREF_NO_BIG_NOTIFICATIONS); settingKeys.add(pkgName + Common.PREF_INSISTENT_NOTIF); settingKeys.add(pkgName + Common.PREF_ONGOING_NOTIF); if (Build.VERSION.SDK_INT >= 16) settingKeys.add(pkgName + Common.PREF_NOTIF_PRIORITY); settingKeys.add(pkgName + Common.PREF_RECENTS_MODE); settingKeys.add(pkgName + Common.PREF_MUTE); settingKeys.add(pkgName + Common.PREF_LEGACY_MENU); settingKeys.add(pkgName + Common.PREF_REVOKEPERMS); settingKeys.add(pkgName + Common.PREF_REVOKELIST); return settingKeys; } private Map<String, Object> getSettings() { Map<String, Object> settings = new HashMap<String, Object>(); if (swtActive.isChecked()) { settings.put(pkgName + Common.PREF_ACTIVE, true); int dpi; try { dpi = Integer.parseInt(((EditText) findViewById(R.id.txtDPI)).getText().toString()); } catch (Exception ex) { dpi = 0; } if (dpi != 0) settings.put(pkgName + Common.PREF_DPI, dpi); int fontScale; try { fontScale = Integer.parseInt(((EditText) findViewById(R.id.txtFontScale)).getText().toString()); } catch (Exception ex) { fontScale = 0; } if (fontScale != 0 && fontScale != 100) settings.put(pkgName + Common.PREF_FONT_SCALE, fontScale); int screen = ((Spinner) findViewById(R.id.spnScreen)).getSelectedItemPosition(); if (screen > 0) settings.put(pkgName + Common.PREF_SCREEN, screen); if (((CheckBox) findViewById(R.id.chkXlarge)).isChecked()) settings.put(pkgName + Common.PREF_XLARGE, true); if (((CheckBox) findViewById(R.id.chkResOnWidgets)).isChecked()) settings.put(pkgName + Common.PREF_RES_ON_WIDGETS, true); int selectedLocalePos = ((Spinner) findViewById(R.id.spnLocale)).getSelectedItemPosition(); if (selectedLocalePos > 0) settings.put(pkgName + Common.PREF_LOCALE, localeList.getLocale(selectedLocalePos)); int fullscreen = ((Spinner) findViewById(R.id.spnFullscreen)).getSelectedItemPosition(); if (fullscreen > 0) settings.put(pkgName + Common.PREF_FULLSCREEN, fullscreen); if (((CheckBox) findViewById(R.id.chkNoTitle)).isChecked()) settings.put(pkgName + Common.PREF_NO_TITLE, true); if (((CheckBox) findViewById(R.id.chkAllowOnLockscreen)).isChecked()) settings.put(pkgName + Common.PREF_ALLOW_ON_LOCKSCREEN, true); if (((CheckBox) findViewById(R.id.chkScreenOn)).isChecked()) settings.put(pkgName + Common.PREF_SCREEN_ON, true); int orientation = ((Spinner) findViewById(R.id.spnOrientation)).getSelectedItemPosition(); if (orientation > 0) settings.put(pkgName + Common.PREF_ORIENTATION, orientation); if (((CheckBox) findViewById(R.id.chkResident)).isChecked()) settings.put(pkgName + Common.PREF_RESIDENT, true); if (((CheckBox) findViewById(R.id.chkNoFullscreenIME)).isChecked()) settings.put(pkgName + Common.PREF_NO_FULLSCREEN_IME, true); if (((CheckBox) findViewById(R.id.chkNoBigNotifications)).isChecked()) settings.put(pkgName + Common.PREF_NO_BIG_NOTIFICATIONS, true); if (((CheckBox) findViewById(R.id.chkInsistentNotifications)).isChecked()) settings.put(pkgName + Common.PREF_INSISTENT_NOTIF, true); int ongoingNotif = ((Spinner) findViewById(R.id.spnOngoingNotifications)).getSelectedItemPosition(); if (ongoingNotif > 0) settings.put(pkgName + Common.PREF_ONGOING_NOTIF, ongoingNotif); if (Build.VERSION.SDK_INT >= 16) { int notifPriority = ((Spinner) findViewById(R.id.spnNotifPriority)).getSelectedItemPosition(); if (notifPriority > 0) settings.put(pkgName + Common.PREF_NOTIF_PRIORITY, notifPriority); } int recentsMode = ((Spinner) findViewById(R.id.spnRecentsMode)).getSelectedItemPosition(); if (recentsMode > 0) settings.put(pkgName + Common.PREF_RECENTS_MODE, recentsMode); if (((CheckBox) findViewById(R.id.chkMute)).isChecked()) settings.put(pkgName + Common.PREF_MUTE, true); if (((CheckBox) findViewById(R.id.chkLegacyMenu)).isChecked()) settings.put(pkgName + Common.PREF_LEGACY_MENU, true); if (allowRevoking) settings.put(pkgName + Common.PREF_REVOKEPERMS, true); if (disabledPermissions.size() > 0) settings.put(pkgName + Common.PREF_REVOKELIST, new HashSet<String>(disabledPermissions)); } return settings; } @Override public void onBackPressed() { // If form wasn't changed, exit without prompting if (getSettings().equals(initialSettings)) { finish(); return; } // Require confirmation to exit the screen and lose configuration changes AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.settings_unsaved_title); builder.setIconAttribute(android.R.attr.alertDialogIcon); builder.setMessage(R.string.settings_unsaved_detail); builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ApplicationSettings.this.finish(); } }); builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); builder.show(); } @Override protected void onDestroy() { super.onDestroy(); setResult(RESULT_OK, parentIntent); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_app, menu); updateMenuEntries(getApplicationContext(), menu, pkgName); return true; } public static void updateMenuEntries(Context context, Menu menu, String pkgName) { if (context.getPackageManager().getLaunchIntentForPackage(pkgName) == null) { menu.findItem(R.id.menu_app_launch).setEnabled(false); Drawable icon = menu.findItem(R.id.menu_app_launch).getIcon().mutate(); icon.setColorFilter(Color.GRAY, Mode.SRC_IN); menu.findItem(R.id.menu_app_launch).setIcon(icon); } boolean hasMarketLink = false; try { PackageManager pm = context.getPackageManager(); String installer = pm.getInstallerPackageName(pkgName); if (installer != null) hasMarketLink = installer.equals("com.android.vending") || installer.contains("google"); } catch (Exception e) { } menu.findItem(R.id.menu_app_store).setEnabled(hasMarketLink); try { Resources res = context.createPackageContext("com.android.vending", 0).getResources(); int id = res.getIdentifier("ic_launcher_play_store", "mipmap", "com.android.vending"); Drawable icon = res.getDrawable(id); if (!hasMarketLink) { icon = icon.mutate(); icon.setColorFilter(Color.GRAY, Mode.SRC_IN); } menu.findItem(R.id.menu_app_store).setIcon(icon); } catch (Exception e) { } } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.menu_save) { Editor prefsEditor = prefs.edit(); Map<String, Object> newSettings = getSettings(); for (String key : settingKeys) { Object value = newSettings.get(key); if (value == null) { prefsEditor.remove(key); } else { if (value instanceof Boolean) { prefsEditor.putBoolean(key, ((Boolean) value).booleanValue()); } else if (value instanceof Integer) { prefsEditor.putInt(key, ((Integer) value).intValue()); } else if (value instanceof String) { prefsEditor.putString(key, (String) value); } else if (value instanceof Set) { prefsEditor.remove(key); // Commit and reopen the editor, as it seems to be bugged when updating a StringSet prefsEditor.commit(); prefsEditor = prefs.edit(); prefsEditor.putStringSet(key, (Set<String>) value); } else { // Should never happen throw new IllegalStateException("Invalid setting type: " + key + "=" + value); } } } prefsEditor.commit(); // Update saved settings to detect modifications later initialSettings = newSettings; // Check if in addition to saving the settings, the app should also be killed AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.settings_apply_title); builder.setMessage(R.string.settings_apply_detail); builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Send the broadcast requesting to kill the app Intent applyIntent = new Intent(Common.MY_PACKAGE_NAME + ".UPDATE_PERMISSIONS"); applyIntent.putExtra("action", Common.ACTION_PERMISSIONS); applyIntent.putExtra("Package", pkgName); applyIntent.putExtra("Kill", true); sendBroadcast(applyIntent, Common.MY_PACKAGE_NAME + ".BROADCAST_PERMISSION"); dialog.dismiss(); } }); builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Send the broadcast but not requesting kill Intent applyIntent = new Intent(Common.MY_PACKAGE_NAME + ".UPDATE_PERMISSIONS"); applyIntent.putExtra("action", Common.ACTION_PERMISSIONS); applyIntent.putExtra("Package", pkgName); applyIntent.putExtra("Kill", false); sendBroadcast(applyIntent, Common.MY_PACKAGE_NAME + ".BROADCAST_PERMISSION"); dialog.dismiss(); } }); builder.create().show(); } else if (item.getItemId() == R.id.menu_app_launch) { Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage(pkgName); startActivity(LaunchIntent); } else if (item.getItemId() == R.id.menu_app_settings) { startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + pkgName))); } else if (item.getItemId() == R.id.menu_app_store) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + pkgName))); } return super.onOptionsItemSelected(item); } }