From fe1812fd38633e3c90abfa022d2d0d4a6029e2bf Mon Sep 17 00:00:00 2001 From: Luis Vidal Date: Wed, 13 Apr 2016 01:08:11 -0700 Subject: [PATCH] Weather API: Delegate the responsability of rejecting back to back requests [1/2] The Weather Manager Service should not impose rules regarding how a weather provide service wants to react to back to back weather update requests, nor impose the time a caller should wait before a new request can be submitted. These constraints vary between weather services, so it's up the each implementation to enforce these constraints. With this patch, the Weather manager service will pass the requests as they come from the requester and it will be up to the active service provider decide whether process or reject the request. Changes to API: - Moved the request statuses to new inner class RequestStatus in CMWeatherManager - Pass status arg to onLookupCityRequestCompleted() - Added reject(int) method to ServiceRequest Change-Id: I3512490688255e25395e955d506fe42ed52f8fe0 TICKET: CYNGNOS-2430 --- api/cm_current.txt | 16 ++- .../internal/CMWeatherManagerService.java | 114 +++++----------- .../cyanogenmod/weather/CMWeatherManager.java | 81 +++++------ .../weather/IRequestInfoListener.aidl | 4 +- .../weatherservice/ServiceRequest.java | 127 ++++++++++++------ system-api/cm_system-current.txt | 16 ++- 6 files changed, 174 insertions(+), 184 deletions(-) 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 {