diff --git a/api/cm_current.txt b/api/cm_current.txt index f1652d3..40d6fa5 100644 --- a/api/cm_current.txt +++ b/api/cm_current.txt @@ -1360,14 +1360,19 @@ package cyanogenmod.weather { method public int requestWeatherUpdate(android.location.Location, cyanogenmod.weather.CMWeatherManager.WeatherUpdateRequestListener); method public int requestWeatherUpdate(cyanogenmod.weather.WeatherLocation, cyanogenmod.weather.CMWeatherManager.WeatherUpdateRequestListener); method public void unregisterWeatherServiceProviderChangeListener(cyanogenmod.weather.CMWeatherManager.WeatherServiceProviderChangeListener); - field public static final int WEATHER_REQUEST_ALREADY_IN_PROGRESS = -3; // 0xfffffffd - field public static final int WEATHER_REQUEST_COMPLETED = 1; // 0x1 - field public static final int WEATHER_REQUEST_FAILED = -2; // 0xfffffffe - field public static final int WEATHER_REQUEST_SUBMITTED_TOO_SOON = -1; // 0xffffffff } public static abstract interface CMWeatherManager.LookupCityRequestListener { - method public abstract void onLookupCityRequestCompleted(java.util.List); + method public abstract void onLookupCityRequestCompleted(int, java.util.List); + } + + public static class CMWeatherManager.RequestStatus { + ctor public CMWeatherManager.RequestStatus(); + field public static final int ALREADY_IN_PROGRESS = -3; // 0xfffffffd + field public static final int COMPLETED = 1; // 0x1 + field public static final int FAILED = -1; // 0xffffffff + field public static final int NO_MATCH_FOUND = -4; // 0xfffffffc + field public static final int SUBMITTED_TOO_SOON = -2; // 0xfffffffe } public static abstract interface CMWeatherManager.WeatherServiceProviderChangeListener { @@ -1468,6 +1473,7 @@ package cyanogenmod.weatherservice { method public void complete(cyanogenmod.weatherservice.ServiceRequestResult); method public void fail(); method public cyanogenmod.weather.RequestInfo getRequestInfo(); + method public void reject(int); } public final class ServiceRequestResult implements android.os.Parcelable { diff --git a/cm/lib/main/java/org/cyanogenmod/platform/internal/CMWeatherManagerService.java b/cm/lib/main/java/org/cyanogenmod/platform/internal/CMWeatherManagerService.java index 69392fd..856bf2a 100644 --- a/cm/lib/main/java/org/cyanogenmod/platform/internal/CMWeatherManagerService.java +++ b/cm/lib/main/java/org/cyanogenmod/platform/internal/CMWeatherManagerService.java @@ -31,7 +31,6 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.os.SystemClock; import android.os.UserHandle; import android.text.TextUtils; import android.util.Slog; @@ -58,16 +57,9 @@ import java.util.List; public class CMWeatherManagerService extends SystemService{ private static final String TAG = CMWeatherManagerService.class.getSimpleName(); - /** - * How long clients will have to wait until a new weather update request can be honored - * TODO Allow weather service providers to specify this threshold - */ - private static final long REQUEST_THRESHOLD_MILLIS = 1000L * 60L * 10L; private IWeatherProviderService mWeatherProviderService; private boolean mIsWeatherProviderServiceBound; - private long mLastWeatherUpdateRequestTimestamp = -REQUEST_THRESHOLD_MILLIS; - private boolean mIsProcessingRequest = false; private Object mMutex = new Object(); private Context mContext; private final RemoteCallbackList mProviderChangeListeners @@ -78,12 +70,16 @@ public class CMWeatherManagerService extends SystemService{ = new IWeatherProviderServiceClient.Stub() { @Override public void setServiceRequestState(RequestInfo requestInfo, - ServiceRequestResult result, int state) { + ServiceRequestResult result, int status) { synchronized (mMutex) { if (requestInfo == null) { //Invalid request info object - mIsProcessingRequest = false; + return; + } + + if (!isValidRequestInfoStatus(status)) { + //Invalid request status return; } @@ -93,19 +89,14 @@ public class CMWeatherManagerService extends SystemService{ switch (requestType) { case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ: case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ: - if (!isValidRequestInfoState(requestType, state)) { - //We received an invalid state, silently disregard the request - mIsProcessingRequest = false; - return; - } WeatherInfo weatherInfo = null; - if (state == CMWeatherManager.WEATHER_REQUEST_COMPLETED) { + if (status == CMWeatherManager.RequestStatus.COMPLETED) { weatherInfo = (result != null) ? result.getWeatherInfo() : null; if (weatherInfo == null) { //This should never happen! WEATHER_REQUEST_COMPLETED is set //only if the weatherinfo object was not null when the request //was marked as completed - state = CMWeatherManager.WEATHER_REQUEST_FAILED; + status = CMWeatherManager.RequestStatus.FAILED; } else { if (!requestInfo.isQueryOnlyWeatherRequest()) { final long identity = Binder.clearCallingIdentity(); @@ -119,7 +110,8 @@ public class CMWeatherManagerService extends SystemService{ } if (isValidListener(listener)) { try { - listener.onWeatherRequestCompleted(requestInfo, state, weatherInfo); + listener.onWeatherRequestCompleted(requestInfo, status, + weatherInfo); } catch (RemoteException e) { } } @@ -128,40 +120,25 @@ public class CMWeatherManagerService extends SystemService{ if (isValidListener(listener)) { try { //Result might be null if the provider marked the request as failed - listener.onLookupCityRequestCompleted(requestInfo, + listener.onLookupCityRequestCompleted(requestInfo, status, result != null ? result.getLocationLookupList() : null); } catch (RemoteException e) { } } break; } - mIsProcessingRequest = false; } } }; - private boolean isValidRequestInfoState(int requestType, int state) { - switch (requestType) { - case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ: - case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ: - switch (state) { - case CMWeatherManager.WEATHER_REQUEST_COMPLETED: - case CMWeatherManager.WEATHER_REQUEST_SUBMITTED_TOO_SOON: - case CMWeatherManager.WEATHER_REQUEST_FAILED: - case CMWeatherManager.WEATHER_REQUEST_ALREADY_IN_PROGRESS: - return true; - default: - return false; - } - case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ: - switch (state) { - case CMWeatherManager.LOOKUP_REQUEST_COMPLETED: - case CMWeatherManager.LOOKUP_REQUEST_FAILED: - case CMWeatherManager.LOOKUP_REQUEST_NO_MATCH_FOUND: - return true; - default: - return false; - } + private boolean isValidRequestInfoStatus(int state) { + switch (state) { + case CMWeatherManager.RequestStatus.COMPLETED: + case CMWeatherManager.RequestStatus.ALREADY_IN_PROGRESS: + case CMWeatherManager.RequestStatus.FAILED: + case CMWeatherManager.RequestStatus.NO_MATCH_FOUND: + case CMWeatherManager.RequestStatus.SUBMITTED_TOO_SOON: + return true; default: return false; } @@ -271,36 +248,14 @@ public class CMWeatherManagerService extends SystemService{ } } - private boolean canProcessWeatherUpdateRequest(RequestInfo info, long currentTimeMillis) { + private boolean canProcessWeatherUpdateRequest(RequestInfo info) { final IRequestInfoListener listener = info.getRequestListener(); - if ((mLastWeatherUpdateRequestTimestamp + REQUEST_THRESHOLD_MILLIS) > currentTimeMillis) { - if (listener != null && listener.asBinder().pingBinder()) { - try { - listener.onWeatherRequestCompleted(info, - CMWeatherManager.WEATHER_REQUEST_SUBMITTED_TOO_SOON, null); - } catch (RemoteException e) { - } - } - return false; - } - - if (mIsProcessingRequest) { - if (listener != null && listener.asBinder().pingBinder()) { - try { - listener.onWeatherRequestCompleted(info, - CMWeatherManager.WEATHER_REQUEST_ALREADY_IN_PROGRESS, null); - } catch (RemoteException e) { - } - } - return false; - } - if (!mIsWeatherProviderServiceBound) { if (listener != null && listener.asBinder().pingBinder()) { try { listener.onWeatherRequestCompleted(info, - CMWeatherManager.WEATHER_REQUEST_FAILED, null); + CMWeatherManager.RequestStatus.FAILED, null); } catch (RemoteException e) { } } @@ -310,12 +265,7 @@ public class CMWeatherManagerService extends SystemService{ } private synchronized void processWeatherUpdateRequest(RequestInfo info) { - final long currentTimeMillis = SystemClock.elapsedRealtime(); - - if (!canProcessWeatherUpdateRequest(info, currentTimeMillis)) return; - - mLastWeatherUpdateRequestTimestamp = currentTimeMillis; - mIsProcessingRequest = true; + if (!canProcessWeatherUpdateRequest(info)) return; try { mWeatherProviderService.processWeatherUpdateRequest(info); } catch (RemoteException e) { @@ -327,13 +277,13 @@ public class CMWeatherManagerService extends SystemService{ final IRequestInfoListener listener = info.getRequestListener(); if (listener != null && listener.asBinder().pingBinder()) { try { - listener.onLookupCityRequestCompleted(info, null); + listener.onLookupCityRequestCompleted(info, + CMWeatherManager.RequestStatus.FAILED, null); } catch (RemoteException e) { } } return; } - try { mWeatherProviderService.processCityNameLookupRequest(info); } catch(RemoteException e){ @@ -368,9 +318,6 @@ public class CMWeatherManagerService extends SystemService{ public void onServiceDisconnected(ComponentName name) { mWeatherProviderService = null; mIsWeatherProviderServiceBound = false; - //We can't talk to the current service anyway... - mIsProcessingRequest = false; - mLastWeatherUpdateRequestTimestamp = -REQUEST_THRESHOLD_MILLIS; Slog.d(TAG, "Connection with " + name.flattenToString() + " has been closed"); } }; @@ -543,16 +490,17 @@ public class CMWeatherManagerService extends SystemService{ private synchronized void disconnectClient() { if (mIsWeatherProviderServiceBound) { - if (mIsProcessingRequest) { - try { - mWeatherProviderService.cancelOngoingRequests(); - } catch (RemoteException e) { - } - mIsProcessingRequest = false; + //let's cancel any pending request + try { + mWeatherProviderService.cancelOngoingRequests(); + } catch (RemoteException e) { + Slog.d(TAG, "Error occurred while trying to cancel ongoing requests"); } + //Disconnect from client try { mWeatherProviderService.setServiceClient(null); } catch (RemoteException e) { + Slog.d(TAG, "Error occurred while disconnecting client"); } getContext().unbindService(mWeatherServiceProviderConnection); diff --git a/sdk/src/java/cyanogenmod/weather/CMWeatherManager.java b/sdk/src/java/cyanogenmod/weather/CMWeatherManager.java index 545c3ce..8292b58 100644 --- a/sdk/src/java/cyanogenmod/weather/CMWeatherManager.java +++ b/sdk/src/java/cyanogenmod/weather/CMWeatherManager.java @@ -53,40 +53,32 @@ public class CMWeatherManager { private static final String TAG = CMWeatherManager.class.getSimpleName(); - /** - * Weather update request state: Successfully completed - */ - public static final int WEATHER_REQUEST_COMPLETED = 1; /** - * Weather update request state: You need to wait a bit longer before requesting an update - * again. - *

Please bear in mind that the weather does not change very often. A threshold of 10 minutes - * is enforced by the system

+ * The different request statuses */ - public static final int WEATHER_REQUEST_SUBMITTED_TOO_SOON = -1; - - /** - * Weather update request state: An error occurred while trying to update the weather. You - * should wait before trying again, or your request will be rejected with - * {@link #WEATHER_REQUEST_SUBMITTED_TOO_SOON} - */ - public static final int WEATHER_REQUEST_FAILED = -2; - - /** - * Weather update request state: Only one update request can be processed at a given time. - */ - public static final int WEATHER_REQUEST_ALREADY_IN_PROGRESS = -3; - - /** @hide */ - public static final int LOOKUP_REQUEST_COMPLETED = 100; - - /** @hide */ - public static final int LOOKUP_REQUEST_FAILED = -100; - - /** @hide */ - public static final int LOOKUP_REQUEST_NO_MATCH_FOUND = -101; - + public static class RequestStatus { + /** + * Request Successfully completed + */ + public static final int COMPLETED = 1; + /** + * An error occurred while trying to honor the request. + */ + public static final int FAILED = -1; + /** + * The request can't be processed at this time + */ + public static final int SUBMITTED_TOO_SOON = -2; + /** + * Another request in already in progress + */ + public static final int ALREADY_IN_PROGRESS = -3; + /** + * No match found for the query + */ + public static final int NO_MATCH_FOUND = -4; + } private CMWeatherManager(Context context) { Context appContext = context.getApplicationContext(); @@ -330,7 +322,7 @@ public class CMWeatherManager { private final IRequestInfoListener mRequestInfoListener = new IRequestInfoListener.Stub() { @Override - public void onWeatherRequestCompleted(final RequestInfo requestInfo, final int state, + public void onWeatherRequestCompleted(final RequestInfo requestInfo, final int status, final WeatherInfo weatherInfo) { final WeatherUpdateRequestListener listener = mWeatherUpdateRequestListeners.remove(requestInfo); @@ -338,14 +330,14 @@ public class CMWeatherManager { mHandler.post(new Runnable() { @Override public void run() { - listener.onWeatherRequestCompleted(state, weatherInfo); + listener.onWeatherRequestCompleted(status, weatherInfo); } }); } } @Override - public void onLookupCityRequestCompleted(RequestInfo requestInfo, + public void onLookupCityRequestCompleted(RequestInfo requestInfo, final int status, final List weatherLocations) { final LookupCityRequestListener listener @@ -354,7 +346,7 @@ public class CMWeatherManager { mHandler.post(new Runnable() { @Override public void run() { - listener.onLookupCityRequestCompleted(weatherLocations); + listener.onLookupCityRequestCompleted(status, weatherLocations); } }); } @@ -369,16 +361,12 @@ public class CMWeatherManager { * This method will be called when the weather service provider has finished processing the * request * - * @param state Any of the following values - * {@link #WEATHER_REQUEST_COMPLETED} - * {@link #WEATHER_REQUEST_ALREADY_IN_PROGRESS} - * {@link #WEATHER_REQUEST_SUBMITTED_TOO_SOON} - * {@link #WEATHER_REQUEST_FAILED} + * @param status See {@link RequestStatus} * * @param weatherInfo A fully populated {@link WeatherInfo} if state is - * {@link #WEATHER_REQUEST_COMPLETED}, null otherwise + * {@link RequestStatus#COMPLETED}, null otherwise */ - void onWeatherRequestCompleted(int state, WeatherInfo weatherInfo); + void onWeatherRequestCompleted(int status, WeatherInfo weatherInfo); } /** @@ -387,11 +375,14 @@ public class CMWeatherManager { public interface LookupCityRequestListener { /** * This method will be called when the weather service provider has finished processing the - * request. The argument can be null if the provider couldn't find a match + * request. * - * @param locations + * @param status See {@link RequestStatus} + * + * @param locations A list of {@link WeatherLocation} if the status is + * {@link RequestStatus#COMPLETED}, null otherwise */ - void onLookupCityRequestCompleted(List locations); + void onLookupCityRequestCompleted(int status, List locations); } /** diff --git a/sdk/src/java/cyanogenmod/weather/IRequestInfoListener.aidl b/sdk/src/java/cyanogenmod/weather/IRequestInfoListener.aidl index 553da71..d35db44 100644 --- a/sdk/src/java/cyanogenmod/weather/IRequestInfoListener.aidl +++ b/sdk/src/java/cyanogenmod/weather/IRequestInfoListener.aidl @@ -24,8 +24,8 @@ import java.util.List; /** @hide */ oneway interface IRequestInfoListener { - void onWeatherRequestCompleted(in RequestInfo requestInfo, int state, + void onWeatherRequestCompleted(in RequestInfo requestInfo, int status, in WeatherInfo weatherInfo); - void onLookupCityRequestCompleted(in RequestInfo requestInfo, + void onLookupCityRequestCompleted(in RequestInfo requestInfo, int status, in List weatherLocation); } \ No newline at end of file diff --git a/sdk/src/java/cyanogenmod/weatherservice/ServiceRequest.java b/sdk/src/java/cyanogenmod/weatherservice/ServiceRequest.java index bc2f38d..f503a2f 100644 --- a/sdk/src/java/cyanogenmod/weatherservice/ServiceRequest.java +++ b/sdk/src/java/cyanogenmod/weatherservice/ServiceRequest.java @@ -29,15 +29,15 @@ public final class ServiceRequest { private final RequestInfo mInfo; private final IWeatherProviderServiceClient mClient; - /** - * If a request is marked as cancelled, it means the client does not want to know anything about - * this request anymore - */ - private volatile boolean mCancelled; + private enum Status { + IN_PROGRESS, COMPLETED, CANCELLED, FAILED, REJECTED + } + private Status mStatus; /* package */ ServiceRequest(RequestInfo info, IWeatherProviderServiceClient client) { mInfo = info; mClient = client; + mStatus = Status.IN_PROGRESS; } /** @@ -52,32 +52,36 @@ public final class ServiceRequest { * This method should be called once the request has been completed */ public void complete(@NonNull ServiceRequestResult result) { - if (!mCancelled) { - try { - final int requestType = mInfo.getRequestType(); - switch (requestType) { - case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ: - case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ: - if (result.getWeatherInfo() == null) { - throw new IllegalStateException("The service request result does not" - + " contain a valid WeatherInfo object"); - } - mClient.setServiceRequestState(mInfo, result, - CMWeatherManager.WEATHER_REQUEST_COMPLETED); - break; - case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ: - if (result.getLocationLookupList() == null) { - //In case the user decided to mark this request as completed with an - //empty list. It's not necessarily a failure - mClient.setServiceRequestState(mInfo, null, - CMWeatherManager.LOOKUP_REQUEST_NO_MATCH_FOUND); - } else { + synchronized (this) { + if (mStatus.equals(Status.IN_PROGRESS)) { + try { + final int requestType = mInfo.getRequestType(); + switch (requestType) { + case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ: + case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ: + if (result.getWeatherInfo() == null) { + throw new IllegalStateException("The service request result doesn't" + + " contain a valid WeatherInfo object"); + } mClient.setServiceRequestState(mInfo, result, - CMWeatherManager.LOOKUP_REQUEST_COMPLETED); - } - break; + CMWeatherManager.RequestStatus.COMPLETED); + break; + case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ: + if (result.getLocationLookupList() == null + || result.getLocationLookupList().size() <= 0) { + //In case the user decided to mark this request as completed with + //null or empty list. It's not necessarily a failure + mClient.setServiceRequestState(mInfo, null, + CMWeatherManager.RequestStatus.NO_MATCH_FOUND); + } else { + mClient.setServiceRequestState(mInfo, result, + CMWeatherManager.RequestStatus.COMPLETED); + } + break; + } + } catch (RemoteException e) { } - } catch (RemoteException e) { + mStatus = Status.COMPLETED; } } } @@ -87,21 +91,54 @@ public final class ServiceRequest { * (no internet connection, time out, etc.) */ public void fail() { - if (!mCancelled) { - try { - final int requestType = mInfo.getRequestType(); - switch (requestType) { - case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ: - case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ: - mClient.setServiceRequestState(mInfo, null, - CMWeatherManager.WEATHER_REQUEST_FAILED); - break; - case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ: - mClient.setServiceRequestState(mInfo, null, - CMWeatherManager.LOOKUP_REQUEST_FAILED); - break; + synchronized (this) { + if (mStatus.equals(Status.IN_PROGRESS)) { + try { + final int requestType = mInfo.getRequestType(); + switch (requestType) { + case RequestInfo.TYPE_WEATHER_BY_GEO_LOCATION_REQ: + case RequestInfo.TYPE_WEATHER_BY_WEATHER_LOCATION_REQ: + mClient.setServiceRequestState(mInfo, null, + CMWeatherManager.RequestStatus.FAILED); + break; + case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ: + mClient.setServiceRequestState(mInfo, null, + CMWeatherManager.RequestStatus.FAILED); + break; + } + } catch (RemoteException e) { } - } catch (RemoteException e) { + mStatus = Status.FAILED; + } + } + } + + /** + * This method should be called if the service decides not to honor the request. Note this + * method will accept only the following values. + *
    + *
  • {@link cyanogenmod.weather.CMWeatherManager.RequestStatus#SUBMITTED_TOO_SOON}
  • + *
  • {@link cyanogenmod.weather.CMWeatherManager.RequestStatus#ALREADY_IN_PROGRESS}
  • + *
+ * Attempting to pass any other value will get you an IllegalArgumentException + * @param status + */ + public void reject(int status) { + synchronized (this) { + if (mStatus.equals(Status.IN_PROGRESS)) { + switch (status) { + case CMWeatherManager.RequestStatus.ALREADY_IN_PROGRESS: + case CMWeatherManager.RequestStatus.SUBMITTED_TOO_SOON: + try { + mClient.setServiceRequestState(mInfo, null, status); + } catch (RemoteException e) { + e.printStackTrace(); + } + break; + default: + throw new IllegalArgumentException("Can't reject with status " + status); + } + mStatus = Status.REJECTED; } } } @@ -113,6 +150,8 @@ public final class ServiceRequest { * @hide */ public void cancel() { - mCancelled = true; + synchronized (this) { + mStatus = Status.CANCELLED; + } } } diff --git a/system-api/cm_system-current.txt b/system-api/cm_system-current.txt index f1652d3..40d6fa5 100644 --- a/system-api/cm_system-current.txt +++ b/system-api/cm_system-current.txt @@ -1360,14 +1360,19 @@ package cyanogenmod.weather { method public int requestWeatherUpdate(android.location.Location, cyanogenmod.weather.CMWeatherManager.WeatherUpdateRequestListener); method public int requestWeatherUpdate(cyanogenmod.weather.WeatherLocation, cyanogenmod.weather.CMWeatherManager.WeatherUpdateRequestListener); method public void unregisterWeatherServiceProviderChangeListener(cyanogenmod.weather.CMWeatherManager.WeatherServiceProviderChangeListener); - field public static final int WEATHER_REQUEST_ALREADY_IN_PROGRESS = -3; // 0xfffffffd - field public static final int WEATHER_REQUEST_COMPLETED = 1; // 0x1 - field public static final int WEATHER_REQUEST_FAILED = -2; // 0xfffffffe - field public static final int WEATHER_REQUEST_SUBMITTED_TOO_SOON = -1; // 0xffffffff } public static abstract interface CMWeatherManager.LookupCityRequestListener { - method public abstract void onLookupCityRequestCompleted(java.util.List); + method public abstract void onLookupCityRequestCompleted(int, java.util.List); + } + + public static class CMWeatherManager.RequestStatus { + ctor public CMWeatherManager.RequestStatus(); + field public static final int ALREADY_IN_PROGRESS = -3; // 0xfffffffd + field public static final int COMPLETED = 1; // 0x1 + field public static final int FAILED = -1; // 0xffffffff + field public static final int NO_MATCH_FOUND = -4; // 0xfffffffc + field public static final int SUBMITTED_TOO_SOON = -2; // 0xfffffffe } public static abstract interface CMWeatherManager.WeatherServiceProviderChangeListener { @@ -1468,6 +1473,7 @@ package cyanogenmod.weatherservice { method public void complete(cyanogenmod.weatherservice.ServiceRequestResult); method public void fail(); method public cyanogenmod.weather.RequestInfo getRequestInfo(); + method public void reject(int); } public final class ServiceRequestResult implements android.os.Parcelable {