diff --git a/res/layout/backend_list_entry.xml b/res/layout/backend_list_entry.xml index d4a1c3f..a3643a3 100644 --- a/res/layout/backend_list_entry.xml +++ b/res/layout/backend_list_entry.xml @@ -39,7 +39,7 @@ android:focusable="false" android:clickable="false" android:tintMode="src_in" - android:tint="?android:attr/textColorPrimary" + android:tint="@color/primary_text_default_material_dark" android:background="?android:selectableItemBackground" android:visibility="gone" android:src="@drawable/info" /> @@ -51,7 +51,7 @@ android:focusable="false" android:clickable="false" android:tintMode="src_in" - android:tint="?android:attr/textColorPrimary" + android:tint="@color/primary_text_default_material_dark" android:background="?android:selectableItemBackground" android:src="@drawable/settings" /> diff --git a/res/layout/settings_activity.xml b/res/layout/settings_activity.xml index e8ae5f3..9051118 100644 --- a/res/layout/settings_activity.xml +++ b/res/layout/settings_activity.xml @@ -4,11 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + c = PreferenceManager.class + .getDeclaredConstructor(Activity.class, int.class); + c.setAccessible(true); + return c.newInstance(this.getActivity(), FIRST_REQUEST_CODE); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private PreferenceScreen getPreferenceScreen() { + try { + Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen"); + m.setAccessible(true); + return (PreferenceScreen) m.invoke(mPreferenceManager); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void setPreferenceScreen(PreferenceScreen preferenceScreen) { + try { + Method m = PreferenceManager.class + .getDeclaredMethod("setPreferences", PreferenceScreen.class); + m.setAccessible(true); + boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen); + if (result && preferenceScreen != null) { + mHavePrefs = true; + if (mInitDone) { + postBindPreferences(); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void dispatchActivityResult(int requestCode, int resultCode, Intent data) { + try { + Method m = PreferenceManager.class + .getDeclaredMethod("dispatchActivityResult", int.class, int.class, + Intent.class); + m.setAccessible(true); + m.invoke(mPreferenceManager, requestCode, resultCode, data); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void dispatchActivityDestroy() { + try { + Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy"); + m.setAccessible(true); + m.invoke(mPreferenceManager); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void dispatchActivityStop() { + try { + Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop"); + m.setAccessible(true); + m.invoke(mPreferenceManager); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public PreferenceScreen inflateFromResource(Context context, int resId, + PreferenceScreen rootPreferences) { + PreferenceScreen preferenceScreen; + try { + Method m = PreferenceManager.class + .getDeclaredMethod("inflateFromResource", Context.class, int.class, + PreferenceScreen.class); + m.setAccessible(true); + preferenceScreen = (PreferenceScreen) m + .invoke(mPreferenceManager, context, resId, rootPreferences); + } catch (Exception e) { + throw new RuntimeException(e); + } + return preferenceScreen; + } + + public PreferenceScreen inflateFromIntent(Intent queryIntent, + PreferenceScreen rootPreferences) { + PreferenceScreen preferenceScreen; + try { + Method m = PreferenceManager.class + .getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class); + m.setAccessible(true); + preferenceScreen = (PreferenceScreen) m + .invoke(mPreferenceManager, queryIntent, rootPreferences); + } catch (Exception e) { + throw new RuntimeException(e); + } + return preferenceScreen; + } +} diff --git a/src/org/microg/nlp/AbstractBackendHelper.java b/src/org/microg/nlp/AbstractBackendHelper.java index ffed375..4f223bb 100644 --- a/src/org/microg/nlp/AbstractBackendHelper.java +++ b/src/org/microg/nlp/AbstractBackendHelper.java @@ -1,15 +1,17 @@ package org.microg.nlp; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.IBinder; import android.os.RemoteException; import android.util.Log; public abstract class AbstractBackendHelper implements ServiceConnection { protected final Context context; protected final Intent serviceIntent; - protected boolean bound; + private boolean bound; private final String TAG; public AbstractBackendHelper(String tag, Context context, Intent serviceIntent) { @@ -22,8 +24,21 @@ public abstract class AbstractBackendHelper implements ServiceConnection { public abstract boolean hasBackend(); + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + bound = true; + Log.d(TAG, "Bound to: " + name); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + bound = false; + Log.d(TAG, "Unbound from: " + name); + } + public void unbind() { if (bound) { + Log.d(TAG, "Unbinding from: " + serviceIntent); if (hasBackend()) { try { close(); @@ -42,6 +57,7 @@ public abstract class AbstractBackendHelper implements ServiceConnection { public boolean bind() { if (!bound) { + Log.d(TAG, "Binding to: " + serviceIntent); try { context.bindService(serviceIntent, this, Context.BIND_AUTO_CREATE); } catch (Exception e) { diff --git a/src/org/microg/nlp/PackageReceiver.java b/src/org/microg/nlp/PackageReceiver.java index f120e80..ef6941a 100644 --- a/src/org/microg/nlp/PackageReceiver.java +++ b/src/org/microg/nlp/PackageReceiver.java @@ -15,6 +15,7 @@ public class PackageReceiver extends BroadcastReceiver { Log.d(TAG, "Intent received: " + intent); Log.d(TAG, "Reloading location service..."); LocationService.reloadLocationService(context); + Log.d(TAG, "Reloading geocoding service..."); GeocodeService.reloadLocationService(context); } } diff --git a/src/org/microg/nlp/Provider.java b/src/org/microg/nlp/Provider.java index 4049af4..755175e 100644 --- a/src/org/microg/nlp/Provider.java +++ b/src/org/microg/nlp/Provider.java @@ -6,4 +6,6 @@ public interface Provider { IBinder getBinder(); void reload(); + + void destroy(); } diff --git a/src/org/microg/nlp/ProviderService.java b/src/org/microg/nlp/ProviderService.java index a655b9b..a993b97 100644 --- a/src/org/microg/nlp/ProviderService.java +++ b/src/org/microg/nlp/ProviderService.java @@ -27,6 +27,12 @@ public abstract class ProviderService extends IntentService return provider.getBinder(); } + @Override + public boolean onUnbind(Intent intent) { + destroyProvider(); + return super.onUnbind(intent); + } + @Override public void onDestroy() { provider = null; @@ -39,6 +45,8 @@ public abstract class ProviderService extends IntentService * @return a new {@link org.microg.nlp.Provider} instance */ protected abstract T createProvider(); + + protected abstract void destroyProvider(); @Override protected void onHandleIntent(Intent intent) { diff --git a/src/org/microg/nlp/geocode/BackendFuser.java b/src/org/microg/nlp/geocode/BackendFuser.java index 4ac4e14..fd8d951 100644 --- a/src/org/microg/nlp/geocode/BackendFuser.java +++ b/src/org/microg/nlp/geocode/BackendFuser.java @@ -11,20 +11,12 @@ import java.util.List; import static org.microg.nlp.api.NlpApiConstants.ACTION_GEOCODER_BACKEND; class BackendFuser { - private final List backendHelpers; + private final List backendHelpers = new ArrayList(); + private final Context context; public BackendFuser(Context context) { - backendHelpers = new ArrayList(); - for (String backend : Preferences - .splitBackendString(new Preferences(context).getGeocoderBackends())) { - String[] parts = backend.split("/"); - if (parts.length == 2) { - Intent intent = new Intent(ACTION_GEOCODER_BACKEND); - intent.setPackage(parts[0]); - intent.setClassName(parts[0], parts[1]); - backendHelpers.add(new BackendHelper(context, intent)); - } - } + this.context = context; + reset(); } public void bind() { @@ -70,4 +62,19 @@ class BackendFuser { } return result; } + + public void reset() { + unbind(); + backendHelpers.clear(); + for (String backend : Preferences + .splitBackendString(new Preferences(context).getGeocoderBackends())) { + String[] parts = backend.split("/"); + if (parts.length == 2) { + Intent intent = new Intent(ACTION_GEOCODER_BACKEND); + intent.setPackage(parts[0]); + intent.setClassName(parts[0], parts[1]); + backendHelpers.add(new BackendHelper(context, intent)); + } + } + } } diff --git a/src/org/microg/nlp/geocode/BackendHelper.java b/src/org/microg/nlp/geocode/BackendHelper.java index a01f246..2f64b93 100644 --- a/src/org/microg/nlp/geocode/BackendHelper.java +++ b/src/org/microg/nlp/geocode/BackendHelper.java @@ -46,7 +46,7 @@ class BackendHelper extends AbstractBackendHelper { @Override public void onServiceConnected(ComponentName name, IBinder service) { - bound = true; + super.onServiceConnected(name, service); backend = GeocoderBackend.Stub.asInterface(service); if (backend != null) { try { @@ -60,8 +60,8 @@ class BackendHelper extends AbstractBackendHelper { @Override public void onServiceDisconnected(ComponentName name) { + super.onServiceDisconnected(name); backend = null; - bound = false; } @Override diff --git a/src/org/microg/nlp/geocode/GeocodeProviderV1.java b/src/org/microg/nlp/geocode/GeocodeProviderV1.java index 71468fb..937c7f9 100644 --- a/src/org/microg/nlp/geocode/GeocodeProviderV1.java +++ b/src/org/microg/nlp/geocode/GeocodeProviderV1.java @@ -8,12 +8,11 @@ import com.android.location.provider.GeocodeProvider; import java.util.List; class GeocodeProviderV1 extends GeocodeProvider implements org.microg.nlp.geocode.GeocodeProvider { - private BackendFuser backendFuser; - private Context context; + private final BackendFuser backendFuser; public GeocodeProviderV1(Context context) { - this.context = context; - reload(); + backendFuser = new BackendFuser(context); + backendFuser.bind(); } @Override @@ -47,10 +46,13 @@ class GeocodeProviderV1 extends GeocodeProvider implements org.microg.nlp.geocod @Override public void reload() { - if (backendFuser != null) { - backendFuser.unbind(); - } - backendFuser = new BackendFuser(context); + backendFuser.unbind(); + backendFuser.reset(); backendFuser.bind(); } + + @Override + public void destroy() { + backendFuser.unbind(); + } } diff --git a/src/org/microg/nlp/geocode/GeocodeServiceV1.java b/src/org/microg/nlp/geocode/GeocodeServiceV1.java index cb2f9bd..9e90e8a 100644 --- a/src/org/microg/nlp/geocode/GeocodeServiceV1.java +++ b/src/org/microg/nlp/geocode/GeocodeServiceV1.java @@ -2,13 +2,23 @@ package org.microg.nlp.geocode; public class GeocodeServiceV1 extends GeocodeService { private static final String TAG = GeocodeServiceV1.class.getName(); + private static GeocodeProviderV1 THE_ONE; public GeocodeServiceV1() { super(TAG); } @Override - protected GeocodeProvider createProvider() { - return new GeocodeProviderV1(this); + protected synchronized GeocodeProvider createProvider() { + if (THE_ONE == null) { + THE_ONE = new GeocodeProviderV1(this); + } + return THE_ONE; + } + + @Override + protected void destroyProvider() { + THE_ONE.destroy(); + THE_ONE = null; } } diff --git a/src/org/microg/nlp/location/BackendFuser.java b/src/org/microg/nlp/location/BackendFuser.java index 05d3163..d6a20c5 100644 --- a/src/org/microg/nlp/location/BackendFuser.java +++ b/src/org/microg/nlp/location/BackendFuser.java @@ -18,14 +18,20 @@ import static org.microg.nlp.api.NlpApiConstants.*; class BackendFuser { private static final String TAG = BackendFuser.class.getName(); - private final List backendHelpers; + private final List backendHelpers = new ArrayList(); private final LocationProvider locationProvider; + private final Context context; private Location forcedLocation; private boolean fusing = false; - public BackendFuser(Context context, LocationProvider provider) { - locationProvider = provider; - backendHelpers = new ArrayList(); + public BackendFuser(Context context, LocationProvider locationProvider) { + this.locationProvider = locationProvider; + this.context = context; + } + + public void reset() { + unbind(); + backendHelpers.clear(); for (String backend : Preferences .splitBackendString(new Preferences(context).getLocationBackends())) { String[] parts = backend.split("/"); @@ -125,6 +131,11 @@ class BackendFuser { return forcedLocation; } + public void destroy() { + unbind(); + backendHelpers.clear(); + } + public static class LocationComparator implements Comparator { public static final LocationComparator INSTANCE = new LocationComparator(); diff --git a/src/org/microg/nlp/location/BackendHelper.java b/src/org/microg/nlp/location/BackendHelper.java index 3f3f830..ca534a3 100644 --- a/src/org/microg/nlp/location/BackendHelper.java +++ b/src/org/microg/nlp/location/BackendHelper.java @@ -90,7 +90,7 @@ class BackendHelper extends AbstractBackendHelper { @Override public void onServiceConnected(ComponentName name, IBinder service) { - bound = true; + super.onServiceConnected(name, service); backend = LocationBackend.Stub.asInterface(service); if (backend != null) { try { @@ -107,8 +107,8 @@ class BackendHelper extends AbstractBackendHelper { @Override public void onServiceDisconnected(ComponentName name) { + super.onServiceDisconnected(name); backend = null; - bound = false; } private class Callback extends LocationCallback.Stub { diff --git a/src/org/microg/nlp/location/LocationProviderV1.java b/src/org/microg/nlp/location/LocationProviderV1.java index f3719f9..1d46550 100644 --- a/src/org/microg/nlp/location/LocationProviderV1.java +++ b/src/org/microg/nlp/location/LocationProviderV1.java @@ -10,9 +10,10 @@ import android.util.Log; import static android.location.LocationProvider.AVAILABLE; -public class LocationProviderV1 extends com.android.location.provider.LocationProvider implements LocationProvider { +public class LocationProviderV1 extends com.android.location.provider.LocationProvider + implements LocationProvider { private static final String TAG = LocationProviderV1.class.getName(); - + private final ThreadHelper helper; private long autoTime = Long.MAX_VALUE; private boolean autoUpdate = false; @@ -110,13 +111,16 @@ public class LocationProviderV1 extends com.android.location.provider.LocationPr @Override public void onEnableLocationTracking(boolean enable) { Log.v(TAG, "onEnableLocationTracking: " + enable); - autoUpdate = true; + autoUpdate = enable; + if (autoUpdate && autoTime != Long.MAX_VALUE) helper.enable(); } @Override public void onSetMinTime(long minTime, WorkSource ws) { Log.v(TAG, "onSetMinTime: " + minTime + " by " + ws); autoTime = minTime; + helper.setTime(autoTime); + if (autoUpdate) helper.enable(); } @Override @@ -143,4 +147,9 @@ public class LocationProviderV1 extends com.android.location.provider.LocationPr public void onRemoveListener(int uid, WorkSource ws) { } + + @Override + public void destroy() { + helper.destroy(); + } } diff --git a/src/org/microg/nlp/location/LocationProviderV2.java b/src/org/microg/nlp/location/LocationProviderV2.java index 1f556a4..e659723 100644 --- a/src/org/microg/nlp/location/LocationProviderV2.java +++ b/src/org/microg/nlp/location/LocationProviderV2.java @@ -46,6 +46,11 @@ class LocationProviderV2 extends LocationProviderBase implements LocationProvide helper.reload(); } + @Override + public void destroy() { + helper.destroy(); + } + @Override public void onEnable() { } diff --git a/src/org/microg/nlp/location/LocationServiceV1.java b/src/org/microg/nlp/location/LocationServiceV1.java index 822f398..252a753 100644 --- a/src/org/microg/nlp/location/LocationServiceV1.java +++ b/src/org/microg/nlp/location/LocationServiceV1.java @@ -2,13 +2,23 @@ package org.microg.nlp.location; public class LocationServiceV1 extends LocationService { private static final String TAG = LocationServiceV1.class.getName(); + private static LocationProviderV1 THE_ONE; public LocationServiceV1() { super(TAG); } @Override - protected LocationProvider createProvider() { - return new LocationProviderV1(this); + protected synchronized LocationProvider createProvider() { + if (THE_ONE == null) { + THE_ONE = new LocationProviderV1(this); + } + return THE_ONE; + } + + @Override + protected void destroyProvider() { + THE_ONE.destroy(); + THE_ONE = null; } } diff --git a/src/org/microg/nlp/location/LocationServiceV2.java b/src/org/microg/nlp/location/LocationServiceV2.java index 84237d2..25a690b 100644 --- a/src/org/microg/nlp/location/LocationServiceV2.java +++ b/src/org/microg/nlp/location/LocationServiceV2.java @@ -2,13 +2,23 @@ package org.microg.nlp.location; public class LocationServiceV2 extends LocationService { private static final String TAG = LocationServiceV2.class.getName(); + private static LocationProviderV2 THE_ONE; public LocationServiceV2() { super(TAG); } @Override - protected LocationProvider createProvider() { - return new LocationProviderV2(this); + protected synchronized LocationProvider createProvider() { + if (THE_ONE == null) { + THE_ONE = new LocationProviderV2(this); + } + return THE_ONE; + } + + @Override + protected void destroyProvider() { + THE_ONE.destroy(); + THE_ONE = null; } } diff --git a/src/org/microg/nlp/location/ThreadHelper.java b/src/org/microg/nlp/location/ThreadHelper.java index b606c0b..e0f9931 100644 --- a/src/org/microg/nlp/location/ThreadHelper.java +++ b/src/org/microg/nlp/location/ThreadHelper.java @@ -2,30 +2,23 @@ package org.microg.nlp.location; import android.content.Context; import android.location.Location; +import android.util.Log; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; class ThreadHelper implements Runnable { + private static final String TAG = ThreadHelper.class.getName(); private final Context context; - private final LocationProvider locationProvider; - private BackendFuser backendFuser; + private final BackendFuser backendFuser; private ScheduledThreadPoolExecutor executor; - private long time = 5000; // Initialize with 5s - private boolean enabled; + private long time = 60000; // Initialize with 60s + private AtomicBoolean enabled = new AtomicBoolean(false); public ThreadHelper(Context context, LocationProvider locationProvider) { this.context = context; - this.locationProvider = locationProvider; - updateBackendHandler(); - } - - private void updateBackendHandler() { - BackendFuser old = backendFuser; backendFuser = new BackendFuser(context, locationProvider); - if (old != null) { - backendFuser.forceLocation(old.getForcedLocation()); - } } public void forceLocation(Location location) { @@ -34,7 +27,7 @@ class ThreadHelper implements Runnable { public void reload() { disable(); - updateBackendHandler(); + backendFuser.reset(); enable(); } @@ -43,10 +36,8 @@ class ThreadHelper implements Runnable { executor.shutdownNow(); executor = null; } - if (enabled) { - backendFuser.unbind(); - enabled = false; - } + backendFuser.unbind(); + enabled.set(false); } public void setTime(long time) { @@ -63,9 +54,8 @@ class ThreadHelper implements Runnable { } public void enable() { - if (!enabled) { + if (enabled.compareAndSet(false, true)) { backendFuser.bind(); - enabled = true; } reset(); } @@ -74,4 +64,11 @@ class ThreadHelper implements Runnable { public void run() { backendFuser.update(); } + + public void destroy() { + if (executor != null) { + executor.shutdownNow(); + } + backendFuser.destroy(); + } } diff --git a/src/org/microg/nlp/ui/AbstractBackendPreference.java b/src/org/microg/nlp/ui/AbstractBackendPreference.java index a60d233..337bf77 100644 --- a/src/org/microg/nlp/ui/AbstractBackendPreference.java +++ b/src/org/microg/nlp/ui/AbstractBackendPreference.java @@ -96,7 +96,6 @@ public abstract class AbstractBackendPreference extends DialogPreference { ServiceInfo serviceInfo = info.serviceInfo; String simpleName = String .valueOf(serviceInfo.loadLabel(getContext().getPackageManager())); - Log.d("nlp.IntentToBackend", intent.getAction() + ": " + serviceInfo); knownBackends.add(new BackendInfo(serviceInfo, simpleName)); } return knownBackends; diff --git a/src/org/microg/nlp/ui/SettingsActivity.java b/src/org/microg/nlp/ui/SettingsActivity.java index 1c1dacf..079d4cd 100644 --- a/src/org/microg/nlp/ui/SettingsActivity.java +++ b/src/org/microg/nlp/ui/SettingsActivity.java @@ -1,40 +1,30 @@ package org.microg.nlp.ui; import android.os.Bundle; -import android.preference.PreferenceActivity; +import android.support.v4.preference.PreferenceFragment; +import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; import org.microg.nlp.R; -public class SettingsActivity extends PreferenceActivity { - private Toolbar toolbar; - +public class SettingsActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.nlp_preferences); - toolbar.setTitle(getTitle()); + setContentView(R.layout.settings_activity); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + getSupportFragmentManager().beginTransaction() + .replace(R.id.content_wrapper, new MyPreferenceFragment()).commit(); } - @Override - public void setContentView(int layoutResID) { - ViewGroup contentView = (ViewGroup) LayoutInflater.from(this) - .inflate(R.layout.settings_activity, new LinearLayout(this), false); + public static class MyPreferenceFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - toolbar = (Toolbar) contentView.findViewById(R.id.action_bar); - toolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - ViewGroup contentWrapper = (ViewGroup) contentView.findViewById(R.id.content_wrapper); - LayoutInflater.from(this).inflate(layoutResID, contentWrapper, true); - - getWindow().setContentView(contentView); + addPreferencesFromResource(R.xml.nlp_preferences); + } } }