Safer preference managing. Fix "compact layout requires reload".
Previously, everybody had to remember the preference name and the default value. If it was ever changed, this would have to be updated everywhere. Now, the Preferences class is responsible for talking to the SharedPreferences functionality of ANdroid. I've started with just the compactlayout preference, because that is what I required for this fix.
This commit is contained in:
parent
bc77804eee
commit
af2a9ecfb6
@ -84,8 +84,8 @@
|
||||
android:value="FDroid" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name="Preferences"
|
||||
android:label="Preferences"
|
||||
android:name=".PreferencesActivity"
|
||||
android:parentActivityName="FDroid" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
|
@ -75,6 +75,6 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/icon"
|
||||
android:paddingLeft="6dp" />
|
||||
android:paddingLeft="@dimen/applist_summary_padding" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
4
res/values/dimen.xml
Normal file
4
res/values/dimen.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="applist_summary_padding">6dp</dimen>
|
||||
</resources>
|
@ -22,7 +22,6 @@ package org.fdroid.fdroid;
|
||||
import android.content.*;
|
||||
import android.content.res.Configuration;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
@ -149,7 +148,7 @@ public class FDroid extends FragmentActivity {
|
||||
return true;
|
||||
|
||||
case PREFERENCES:
|
||||
Intent prefs = new Intent(getBaseContext(), Preferences.class);
|
||||
Intent prefs = new Intent(getBaseContext(), PreferencesActivity.class);
|
||||
startActivityForResult(prefs, REQUEST_PREFS);
|
||||
return true;
|
||||
|
||||
|
@ -36,6 +36,11 @@ public class FDroidApp extends Application {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
// Needs to be setup before anything else tries to access it.
|
||||
// Perhaps the constructor is a better place, but then again,
|
||||
// it is more deterministic as to when this gets called...
|
||||
Preferences.setup(this);
|
||||
|
||||
// Clear cached apk files. We used to just remove them after they'd
|
||||
// been installed, but this causes problems for proprietary gapps
|
||||
// users since the introduction of verification (on pre-4.2 Android),
|
||||
|
@ -1,59 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2010-12 Ciaran Gultnieks, ciaran@ciarang.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.File;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.widget.Toast;
|
||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.prefs.PreferenceChangeListener;
|
||||
|
||||
public class Preferences extends PreferenceActivity implements
|
||||
OnPreferenceClickListener {
|
||||
/**
|
||||
* Handles shared preferences for FDroid, looking after the names of
|
||||
* preferences, default values and caching. Needs to be setup in the FDroidApp
|
||||
* (using {@link Preferences#setup(android.content.Context)} before it gets
|
||||
* accessed via the {@link org.fdroid.fdroid.Preferences#get()}
|
||||
* singleton method.
|
||||
*/
|
||||
public class Preferences implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private final SharedPreferences preferences;
|
||||
|
||||
private Preferences(Context context) {
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
private static final String PREF_COMPACT_LAYOUT = "compactlayout";
|
||||
private static final boolean DEFAULT_COMPACT_LAYOUT = false;
|
||||
|
||||
private boolean compactLayout = DEFAULT_COMPACT_LAYOUT;
|
||||
|
||||
private Map<String,Boolean> initialized = new HashMap<String,Boolean>();
|
||||
private List<ChangeListener> compactLayoutListeners = new ArrayList<ChangeListener>();
|
||||
|
||||
private boolean isInitialized(String key) {
|
||||
return initialized.containsKey(key) && initialized.get(key);
|
||||
}
|
||||
|
||||
private void initialize(String key) {
|
||||
initialized.put(key, true);
|
||||
}
|
||||
|
||||
private void uninitialize(String key) {
|
||||
initialized.put(key, false);
|
||||
}
|
||||
|
||||
public boolean hasCompactLayout() {
|
||||
if (!isInitialized(PREF_COMPACT_LAYOUT)) {
|
||||
initialize(PREF_COMPACT_LAYOUT);
|
||||
compactLayout = preferences.getBoolean(PREF_COMPACT_LAYOUT, DEFAULT_COMPACT_LAYOUT);
|
||||
}
|
||||
return compactLayout;
|
||||
}
|
||||
|
||||
public void registerCompactLayoutChangeListener(ChangeListener listener) {
|
||||
compactLayoutListeners.add(listener);
|
||||
}
|
||||
|
||||
public void unregisterCompactLayoutChangeListener(ChangeListener listener) {
|
||||
compactLayoutListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
for (String prefkey : new String[] { "ignoreTouchscreen",
|
||||
"showIncompatible" }) {
|
||||
Preference pref = findPreference(prefkey);
|
||||
pref.setOnPreferenceClickListener(this);
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
Log.d("FDroid", "Invalidating preference '" + key + "'.");
|
||||
uninitialize(key);
|
||||
|
||||
if (key.equals(PREF_COMPACT_LAYOUT)) {
|
||||
for ( ChangeListener listener : compactLayoutListeners ) {
|
||||
listener.onPreferenceChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
// Currently only one action is returned.
|
||||
//String key = preference.getKey();
|
||||
//if (key.equals("ignoreTouchscreen") || key.equals("showIncompatible")) {
|
||||
Intent ret = new Intent();
|
||||
ret.putExtra("update", true);
|
||||
setResult(RESULT_OK, ret);
|
||||
return true;
|
||||
//}
|
||||
private static Preferences instance;
|
||||
|
||||
public static void setup(Context context) {
|
||||
if (instance != null) {
|
||||
String error = "Attempted to reinitialize preferences after it " +
|
||||
"has already been initialized in FDroidApp";
|
||||
Log.e("FDroid", error);
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
instance = new Preferences(context);
|
||||
}
|
||||
|
||||
public static Preferences get() {
|
||||
if (instance == null) {
|
||||
String error = "Attempted to access preferences before it " +
|
||||
"has been initialized in FDroidApp";
|
||||
Log.e("FDroid", error);
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static interface ChangeListener {
|
||||
public void onPreferenceChange();
|
||||
}
|
||||
|
||||
}
|
||||
|
59
src/org/fdroid/fdroid/PreferencesActivity.java
Normal file
59
src/org/fdroid/fdroid/PreferencesActivity.java
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2010-12 Ciaran Gultnieks, ciaran@ciarang.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.widget.Toast;
|
||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||
|
||||
public class PreferencesActivity extends PreferenceActivity implements
|
||||
OnPreferenceClickListener {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
for (String prefkey : new String[] { "ignoreTouchscreen",
|
||||
"showIncompatible" }) {
|
||||
Preference pref = findPreference(prefkey);
|
||||
pref.setOnPreferenceClickListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
// Currently only one action is returned.
|
||||
//String key = preference.getKey();
|
||||
//if (key.equals("ignoreTouchscreen") || key.equals("showIncompatible")) {
|
||||
Intent ret = new Intent();
|
||||
ret.putExtra("update", true);
|
||||
setResult(RESULT_OK, ret);
|
||||
return true;
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
@ -13,6 +13,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.*;
|
||||
import org.fdroid.fdroid.DB;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.compat.LayoutCompat;
|
||||
|
||||
@ -21,9 +22,6 @@ abstract public class AppListAdapter extends BaseAdapter {
|
||||
private List<DB.App> items = new ArrayList<DB.App>();
|
||||
private Context mContext;
|
||||
|
||||
private boolean prefCompactLayoutInitialized = false;
|
||||
private boolean prefCompactLayout = false;
|
||||
|
||||
public AppListAdapter(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
@ -55,73 +53,48 @@ abstract public class AppListAdapter extends BaseAdapter {
|
||||
return position;
|
||||
}
|
||||
|
||||
protected boolean hasCompactLayout() {
|
||||
if (!prefCompactLayoutInitialized) {
|
||||
prefCompactLayoutInitialized = true;
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
prefCompactLayout = prefs.getBoolean("compactlayout", false);
|
||||
}
|
||||
return prefCompactLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
boolean init = false;
|
||||
|
||||
boolean compact = Preferences.get().hasCompactLayout();
|
||||
DB.App app = items.get(position);
|
||||
|
||||
if (convertView == null) {
|
||||
convertView = ((LayoutInflater) mContext.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.applistitem, null);
|
||||
init = true;
|
||||
}
|
||||
|
||||
TextView name = (TextView) convertView.findViewById(R.id.name);
|
||||
TextView summary = (TextView) convertView.findViewById(R.id.summary);
|
||||
TextView status = (TextView) convertView.findViewById(R.id.status);
|
||||
TextView license = (TextView) convertView.findViewById(R.id.license);
|
||||
|
||||
DB.App app = items.get(position);
|
||||
|
||||
status.setText(getVersionInfo(app));
|
||||
license.setText(app.license);
|
||||
ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
|
||||
LinearLayout iconContainer = (LinearLayout)convertView.findViewById(R.id.status_icons);
|
||||
ImageView iconInstalled = (ImageView) convertView.findViewById(R.id.icon_status_installed);
|
||||
ImageView iconUpdates = (ImageView) convertView.findViewById(R.id.icon_status_has_updates);
|
||||
|
||||
name.setText(app.name);
|
||||
summary.setText(app.summary);
|
||||
|
||||
ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
|
||||
File icn = new File(DB.getIconsPath(mContext), app.icon);
|
||||
if (icn.exists() && icn.length() > 0) {
|
||||
new Uri.Builder().build();
|
||||
icon.setImageURI(Uri.parse(icn.getPath()));
|
||||
layoutSummary(summary);
|
||||
layoutIcon(icon, app);
|
||||
|
||||
int visibleOnCompact = compact ? View.VISIBLE : View.GONE;
|
||||
int notVisibleOnCompact = compact ? View.GONE : View.VISIBLE;
|
||||
|
||||
iconContainer.setVisibility(visibleOnCompact);
|
||||
status.setVisibility(notVisibleOnCompact);
|
||||
license.setVisibility(notVisibleOnCompact);
|
||||
|
||||
if (!compact) {
|
||||
status.setText(getVersionInfo(app));
|
||||
license.setText(app.license);
|
||||
} else {
|
||||
icon.setImageResource(android.R.drawable.sym_def_app_icon);
|
||||
}
|
||||
status.setText("");
|
||||
license.setText("");
|
||||
|
||||
ImageView iconInstalled = (ImageView) convertView.findViewById(R.id.icon_status_installed);
|
||||
ImageView iconUpdates = (ImageView) convertView.findViewById(R.id.icon_status_has_updates);
|
||||
|
||||
if (init) {
|
||||
|
||||
if (hasCompactLayout()) {
|
||||
|
||||
iconInstalled.setImageResource(R.drawable.ic_cab_done_holo_dark);
|
||||
iconUpdates.setImageResource(R.drawable.ic_menu_refresh);
|
||||
|
||||
status.setVisibility(View.GONE);
|
||||
license.setVisibility(View.GONE);
|
||||
|
||||
RelativeLayout.LayoutParams summaryLayout =
|
||||
new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||
summaryLayout.addRule(RelativeLayout.BELOW, R.id.name);
|
||||
summaryLayout.addRule(LayoutCompat.RelativeLayout.END_OF, R.id.icon);
|
||||
summary.setLayoutParams(summaryLayout);
|
||||
summary.setPadding(0,0,0,0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCompactLayout()) {
|
||||
iconInstalled.setImageResource(R.drawable.ic_cab_done_holo_dark);
|
||||
iconUpdates.setImageResource(R.drawable.ic_menu_refresh);
|
||||
|
||||
if (app.hasUpdates && showStatusUpdate()) {
|
||||
iconUpdates.setVisibility(View.VISIBLE);
|
||||
@ -145,6 +118,54 @@ abstract public class AppListAdapter extends BaseAdapter {
|
||||
return convertView;
|
||||
}
|
||||
|
||||
/**
|
||||
* If an icon exists on disc, we'll use that, otherwise default to the
|
||||
* plain android app icon.
|
||||
*/
|
||||
private void layoutIcon(ImageView iconView, DB.App app) {
|
||||
|
||||
File icn = new File(DB.getIconsPath(mContext), app.icon);
|
||||
if (icn.exists() && icn.length() > 0) {
|
||||
new Uri.Builder().build();
|
||||
iconView.setImageURI(Uri.parse(icn.getPath()));
|
||||
} else {
|
||||
iconView.setImageResource(android.R.drawable.sym_def_app_icon);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* In compact view, the summary sites next to the icon, below the name.
|
||||
* In non-compact view, it sits under the icon, with some padding pushing
|
||||
* it away from the left margin.
|
||||
*/
|
||||
private void layoutSummary(TextView summaryView) {
|
||||
|
||||
if (Preferences.get().hasCompactLayout()) {
|
||||
|
||||
RelativeLayout.LayoutParams summaryLayout =
|
||||
new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||
summaryLayout.addRule(RelativeLayout.BELOW, R.id.name);
|
||||
summaryLayout.addRule(LayoutCompat.RelativeLayout.END_OF, R.id.icon);
|
||||
summaryView.setLayoutParams(summaryLayout);
|
||||
summaryView.setPadding(0,0,0,0);
|
||||
|
||||
} else {
|
||||
|
||||
RelativeLayout.LayoutParams summaryLayout =
|
||||
new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||
summaryLayout.addRule(RelativeLayout.BELOW, R.id.icon);
|
||||
summaryView.setLayoutParams(summaryLayout);
|
||||
float padding = mContext.getResources().getDimension(R.dimen.applist_summary_padding);
|
||||
summaryView.setPadding((int)padding, 0, 0, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private String getVersionInfo(DB.App app) {
|
||||
StringBuilder version = new StringBuilder();
|
||||
if (app.installedVersion != null) {
|
||||
|
@ -2,6 +2,7 @@ package org.fdroid.fdroid.views.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -11,12 +12,24 @@ import org.fdroid.fdroid.*;
|
||||
import org.fdroid.fdroid.views.AppListAdapter;
|
||||
import org.fdroid.fdroid.views.AppListView;
|
||||
|
||||
abstract class AppListFragment extends Fragment implements AdapterView.OnItemClickListener {
|
||||
abstract class AppListFragment extends Fragment implements AdapterView.OnItemClickListener, Preferences.ChangeListener {
|
||||
|
||||
private FDroid parent;
|
||||
|
||||
protected abstract AppListAdapter getAppListAdapter();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Preferences.get().registerCompactLayoutChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Preferences.get().unregisterCompactLayoutChangeListener(this);
|
||||
}
|
||||
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
try {
|
||||
@ -62,4 +75,9 @@ abstract class AppListFragment extends Fragment implements AdapterView.OnItemCli
|
||||
intent.putExtra("appid", app.id);
|
||||
startActivityForResult(intent, FDroid.REQUEST_APPDETAILS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreferenceChange() {
|
||||
getAppListAdapter().notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
@ -40,14 +40,6 @@ public class AvailableAppsFragment extends AppListFragment implements AdapterVie
|
||||
return view;
|
||||
}
|
||||
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int pos,
|
||||
long id) {
|
||||
String category = parent.getItemAtPosition(pos).toString();
|
||||
|
Loading…
x
Reference in New Issue
Block a user