mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-06 18:27:02 +01:00
add stripped down version of weather part of lineage sdk
Makes it possible to use the lineage weather provider without binary jar (This is based on 63a590625c6c76f82e5ef43408a52238b2b34e43 of https://github.com/LineageOS/android_lineage-sdk)
This commit is contained in:
parent
75c99158ae
commit
5f998d8a95
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
import lineageos.weather.IWeatherServiceProviderChangeListener;
|
||||
import lineageos.weather.RequestInfo;
|
||||
|
||||
interface ILineageWeatherManager {
|
||||
oneway void updateWeather(in RequestInfo info);
|
||||
oneway void lookupCity(in RequestInfo info);
|
||||
oneway void registerWeatherServiceProviderChangeListener(
|
||||
in IWeatherServiceProviderChangeListener listener);
|
||||
oneway void unregisterWeatherServiceProviderChangeListener(
|
||||
in IWeatherServiceProviderChangeListener listener);
|
||||
String getActiveWeatherServiceProviderLabel();
|
||||
oneway void cancelRequest(int requestId);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
import lineageos.weather.RequestInfo;
|
||||
import lineageos.weather.WeatherInfo;
|
||||
import lineageos.weather.WeatherLocation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface IRequestInfoListener {
|
||||
void onWeatherRequestCompleted(in RequestInfo requestInfo, int status,
|
||||
in WeatherInfo weatherInfo);
|
||||
void onLookupCityRequestCompleted(in RequestInfo requestInfo, int status,
|
||||
in List<WeatherLocation> weatherLocation);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
/** @hide */
|
||||
oneway interface IWeatherServiceProviderChangeListener {
|
||||
void onWeatherServiceProviderChanged(String providerLabel);
|
||||
}
|
19
app/src/main/aidl/lineageos/weather/RequestInfo.aidl
Normal file
19
app/src/main/aidl/lineageos/weather/RequestInfo.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
parcelable RequestInfo;
|
19
app/src/main/aidl/lineageos/weather/WeatherInfo.aidl
Normal file
19
app/src/main/aidl/lineageos/weather/WeatherInfo.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanongenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
parcelable WeatherInfo;
|
19
app/src/main/aidl/lineageos/weather/WeatherLocation.aidl
Normal file
19
app/src/main/aidl/lineageos/weather/WeatherLocation.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
parcelable WeatherLocation;
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weatherservice;
|
||||
|
||||
import lineageos.weatherservice.IWeatherProviderServiceClient;
|
||||
import lineageos.weather.RequestInfo;
|
||||
|
||||
interface IWeatherProviderService {
|
||||
void processWeatherUpdateRequest(in RequestInfo request);
|
||||
void processCityNameLookupRequest(in RequestInfo request);
|
||||
void setServiceClient(in IWeatherProviderServiceClient client);
|
||||
void cancelOngoingRequests();
|
||||
void cancelRequest(int requestId);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weatherservice;
|
||||
|
||||
import lineageos.weather.RequestInfo;
|
||||
import lineageos.weatherservice.ServiceRequestResult;
|
||||
|
||||
interface IWeatherProviderServiceClient {
|
||||
void setServiceRequestState(in RequestInfo requestInfo, in ServiceRequestResult result,
|
||||
int state);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weatherservice;
|
||||
|
||||
parcelable ServiceRequestResult;
|
31
app/src/main/java/lineageos/app/LineageContextConstants.java
Normal file
31
app/src/main/java/lineageos/app/LineageContextConstants.java
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2015, The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.app;
|
||||
|
||||
|
||||
public final class LineageContextConstants {
|
||||
|
||||
private LineageContextConstants() {
|
||||
// Empty constructor
|
||||
}
|
||||
|
||||
public static final String LINEAGE_WEATHER_SERVICE = "lineageweather";
|
||||
|
||||
public static class Features {
|
||||
public static final String WEATHER_SERVICES = "org.lineageos.weather";
|
||||
}
|
||||
}
|
32
app/src/main/java/lineageos/os/Build.java
Normal file
32
app/src/main/java/lineageos/os/Build.java
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.os;
|
||||
|
||||
|
||||
public class Build {
|
||||
public static class LINEAGE_VERSION_CODES {
|
||||
public static final int APRICOT = 1;
|
||||
public static final int BOYSENBERRY = 2;
|
||||
public static final int CANTALOUPE = 3;
|
||||
public static final int DRAGON_FRUIT = 4;
|
||||
public static final int ELDERBERRY = 5;
|
||||
public static final int FIG = 6;
|
||||
public static final int GUAVA = 7;
|
||||
public static final int HACKBERRY = 8;
|
||||
public static final int ILAMA = 9;
|
||||
}
|
||||
}
|
153
app/src/main/java/lineageos/os/Concierge.java
Normal file
153
app/src/main/java/lineageos/os/Concierge.java
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.os;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import lineageos.os.Build.LINEAGE_VERSION_CODES;
|
||||
|
||||
/**
|
||||
* Simply, Concierge handles your parcels and makes sure they get marshalled and unmarshalled
|
||||
* correctly when cross IPC boundaries even when there is a version mismatch between the client
|
||||
* sdk level and the framework implementation.
|
||||
*
|
||||
* <p>On incoming parcel (to be unmarshalled):
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* ParcelInfo incomingParcelInfo = Concierge.receiveParcel(incomingParcel);
|
||||
* int parcelableVersion = incomingParcelInfo.getParcelVersion();
|
||||
*
|
||||
* // Do unmarshalling steps here iterating over every plausible version
|
||||
*
|
||||
* // Complete the process
|
||||
* incomingParcelInfo.complete();
|
||||
* </pre>
|
||||
*
|
||||
* <p>On outgoing parcel (to be marshalled):
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* ParcelInfo outgoingParcelInfo = Concierge.prepareParcel(incomingParcel);
|
||||
*
|
||||
* // Do marshalling steps here iterating over every plausible version
|
||||
*
|
||||
* // Complete the process
|
||||
* outgoingParcelInfo.complete();
|
||||
* </pre>
|
||||
*/
|
||||
public final class Concierge {
|
||||
|
||||
/** Not instantiable */
|
||||
private Concierge() {
|
||||
// Don't instantiate
|
||||
}
|
||||
|
||||
/**
|
||||
* Since there might be a case where new versions of the lineage framework use applications running
|
||||
* old versions of the protocol (and thus old versions of this class), we need a versioning
|
||||
* system for the parcels sent between the core framework and its sdk users.
|
||||
*
|
||||
* This parcelable version should be the latest version API version listed in
|
||||
* {@link LINEAGE_VERSION_CODES}
|
||||
* @hide
|
||||
*/
|
||||
public static final int PARCELABLE_VERSION = LINEAGE_VERSION_CODES.ILAMA;
|
||||
|
||||
/**
|
||||
* Tell the concierge to receive our parcel, so we can get information from it.
|
||||
*
|
||||
* MUST CALL {@link ParcelInfo#complete()} AFTER UNMARSHALLING.
|
||||
*
|
||||
* @param parcel Incoming parcel to be unmarshalled
|
||||
* @return {@link ParcelInfo} containing parcel information, specifically the version.
|
||||
*/
|
||||
public static ParcelInfo receiveParcel(Parcel parcel) {
|
||||
return new ParcelInfo(parcel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a parcel for the Concierge.
|
||||
*
|
||||
* MUST CALL {@link ParcelInfo#complete()} AFTER MARSHALLING.
|
||||
*
|
||||
* @param parcel Outgoing parcel to be marshalled
|
||||
* @return {@link ParcelInfo} containing parcel information, specifically the version.
|
||||
*/
|
||||
public static ParcelInfo prepareParcel(Parcel parcel) {
|
||||
return new ParcelInfo(parcel, PARCELABLE_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcel header info specific to the Parcel object that is passed in via
|
||||
* {@link #prepareParcel(Parcel)} or {@link #receiveParcel(Parcel)}. The exposed method
|
||||
* of {@link #getParcelVersion()} gets the api level of the parcel object.
|
||||
*/
|
||||
public final static class ParcelInfo {
|
||||
private Parcel mParcel;
|
||||
private int mParcelableVersion;
|
||||
private int mParcelableSize;
|
||||
private int mStartPosition;
|
||||
private int mSizePosition;
|
||||
private boolean mCreation = false;
|
||||
|
||||
ParcelInfo(Parcel parcel) {
|
||||
mCreation = false;
|
||||
mParcel = parcel;
|
||||
mParcelableVersion = parcel.readInt();
|
||||
mParcelableSize = parcel.readInt();
|
||||
mStartPosition = parcel.dataPosition();
|
||||
}
|
||||
|
||||
ParcelInfo(Parcel parcel, int parcelableVersion) {
|
||||
mCreation = true;
|
||||
mParcel = parcel;
|
||||
mParcelableVersion = parcelableVersion;
|
||||
|
||||
// Write parcelable version, make sure to define explicit changes
|
||||
// within {@link #PARCELABLE_VERSION);
|
||||
mParcel.writeInt(mParcelableVersion);
|
||||
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
mSizePosition = parcel.dataPosition();
|
||||
mParcel.writeInt(0);
|
||||
mStartPosition = parcel.dataPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parcel version from the {@link Parcel} received by the Concierge.
|
||||
* @return {@link #PARCELABLE_VERSION} of the {@link Parcel}
|
||||
*/
|
||||
public int getParcelVersion() {
|
||||
return mParcelableVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the {@link ParcelInfo} for the Concierge.
|
||||
*/
|
||||
public void complete() {
|
||||
if (mCreation) {
|
||||
// Go back and write size
|
||||
mParcelableSize = mParcel.dataPosition() - mStartPosition;
|
||||
mParcel.setDataPosition(mSizePosition);
|
||||
mParcel.writeInt(mParcelableSize);
|
||||
mParcel.setDataPosition(mStartPosition + mParcelableSize);
|
||||
} else {
|
||||
mParcel.setDataPosition(mStartPosition + mParcelableSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
245
app/src/main/java/lineageos/providers/WeatherContract.java
Normal file
245
app/src/main/java/lineageos/providers/WeatherContract.java
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.providers;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
/**
|
||||
* The contract between the weather provider and applications.
|
||||
*/
|
||||
public class WeatherContract {
|
||||
|
||||
/**
|
||||
* The authority of the weather content provider
|
||||
*/
|
||||
public static final String AUTHORITY = "org.lineageos.weather";
|
||||
|
||||
/**
|
||||
* A content:// style uri to the authority for the weather provider
|
||||
*/
|
||||
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
|
||||
|
||||
public static class WeatherColumns {
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "weather");
|
||||
|
||||
public static final Uri CURRENT_AND_FORECAST_WEATHER_URI
|
||||
= Uri.withAppendedPath(CONTENT_URI, "current_and_forecast");
|
||||
public static final Uri CURRENT_WEATHER_URI
|
||||
= Uri.withAppendedPath(CONTENT_URI, "current");
|
||||
public static final Uri FORECAST_WEATHER_URI
|
||||
= Uri.withAppendedPath(CONTENT_URI, "forecast");
|
||||
|
||||
/**
|
||||
* The city name
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String CURRENT_CITY = "city";
|
||||
|
||||
/**
|
||||
* A Valid {@link WeatherCode}
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String CURRENT_CONDITION_CODE = "condition_code";
|
||||
|
||||
|
||||
/**
|
||||
* A localized string mapped to the current weather condition code. Note that, if no
|
||||
* locale is found, the string will be in english
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String CURRENT_CONDITION = "condition";
|
||||
|
||||
/**
|
||||
* The current weather temperature
|
||||
* <P>Type: DOUBLE</P>
|
||||
*/
|
||||
public static final String CURRENT_TEMPERATURE = "temperature";
|
||||
|
||||
/**
|
||||
* The unit in which current temperature is reported
|
||||
* <P>Type: INTEGER</P>
|
||||
* Can be one of the following:
|
||||
* <ul>
|
||||
* <li>{@link TempUnit#CELSIUS}</li>
|
||||
* <li>{@link TempUnit#FAHRENHEIT}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final String CURRENT_TEMPERATURE_UNIT = "temperature_unit";
|
||||
|
||||
/**
|
||||
* The current weather humidity
|
||||
* <P>Type: DOUBLE</P>
|
||||
*/
|
||||
public static final String CURRENT_HUMIDITY = "humidity";
|
||||
|
||||
/**
|
||||
* The current wind direction (in degrees)
|
||||
* <P>Type: DOUBLE</P>
|
||||
*/
|
||||
public static final String CURRENT_WIND_DIRECTION = "wind_direction";
|
||||
|
||||
/**
|
||||
* The current wind speed
|
||||
* <P>Type: DOUBLE</P>
|
||||
*/
|
||||
public static final String CURRENT_WIND_SPEED = "wind_speed";
|
||||
|
||||
/**
|
||||
* The unit in which the wind speed is reported
|
||||
* <P>Type: INTEGER</P>
|
||||
* Can be one of the following:
|
||||
* <ul>
|
||||
* <li>{@link WindSpeedUnit#KPH}</li>
|
||||
* <li>{@link WindSpeedUnit#MPH}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final String CURRENT_WIND_SPEED_UNIT = "wind_speed_unit";
|
||||
|
||||
/**
|
||||
* The timestamp when this weather was reported
|
||||
* <P>Type: LONG</P>
|
||||
*/
|
||||
public static final String CURRENT_TIMESTAMP = "timestamp";
|
||||
|
||||
/**
|
||||
* Today's high temperature.
|
||||
* <p>Type: DOUBLE</p>
|
||||
*/
|
||||
public static final String TODAYS_HIGH_TEMPERATURE = "todays_high";
|
||||
|
||||
/**
|
||||
* Today's low temperature.
|
||||
* <p>Type: DOUBLE</p>
|
||||
*/
|
||||
public static final String TODAYS_LOW_TEMPERATURE = "todays_low";
|
||||
|
||||
/**
|
||||
* The forecasted low temperature
|
||||
* <P>Type: DOUBLE</P>
|
||||
*/
|
||||
public static final String FORECAST_LOW = "forecast_low";
|
||||
|
||||
/**
|
||||
* The forecasted high temperature
|
||||
* <P>Type: DOUBLE</P>
|
||||
*/
|
||||
public static final String FORECAST_HIGH = "forecast_high";
|
||||
|
||||
/**
|
||||
* A localized string mapped to the forecasted weather condition code. Note that, if no
|
||||
* locale is found, the string will be in english
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String FORECAST_CONDITION = "forecast_condition";
|
||||
|
||||
/**
|
||||
* The code identifying the forecasted weather condition.
|
||||
* @see #CURRENT_CONDITION_CODE
|
||||
*/
|
||||
public static final String FORECAST_CONDITION_CODE = "forecast_condition_code";
|
||||
|
||||
/**
|
||||
* Temperature units
|
||||
*/
|
||||
public static final class TempUnit {
|
||||
private TempUnit() {}
|
||||
public final static int CELSIUS = 1;
|
||||
public final static int FAHRENHEIT = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wind speed units
|
||||
*/
|
||||
public static final class WindSpeedUnit {
|
||||
private WindSpeedUnit() {}
|
||||
/**
|
||||
* Kilometers per hour
|
||||
*/
|
||||
public final static int KPH = 1;
|
||||
|
||||
/**
|
||||
* Miles per hour
|
||||
*/
|
||||
public final static int MPH = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Weather condition codes
|
||||
*/
|
||||
public static final class WeatherCode {
|
||||
private WeatherCode() {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final static int WEATHER_CODE_MIN = 0;
|
||||
|
||||
public final static int TORNADO = 0;
|
||||
public final static int TROPICAL_STORM = 1;
|
||||
public final static int HURRICANE = 2;
|
||||
public final static int SEVERE_THUNDERSTORMS = 3;
|
||||
public final static int THUNDERSTORMS = 4;
|
||||
public final static int MIXED_RAIN_AND_SNOW = 5;
|
||||
public final static int MIXED_RAIN_AND_SLEET = 6;
|
||||
public final static int MIXED_SNOW_AND_SLEET = 7;
|
||||
public final static int FREEZING_DRIZZLE = 8;
|
||||
public final static int DRIZZLE = 9;
|
||||
public final static int FREEZING_RAIN = 10;
|
||||
public final static int SHOWERS = 11;
|
||||
public final static int SNOW_FLURRIES = 12;
|
||||
public final static int LIGHT_SNOW_SHOWERS = 13;
|
||||
public final static int BLOWING_SNOW = 14;
|
||||
public final static int SNOW = 15;
|
||||
public final static int HAIL = 16;
|
||||
public final static int SLEET = 17;
|
||||
public final static int DUST = 18;
|
||||
public final static int FOGGY = 19;
|
||||
public final static int HAZE = 20;
|
||||
public final static int SMOKY = 21;
|
||||
public final static int BLUSTERY = 22;
|
||||
public final static int WINDY = 23;
|
||||
public final static int COLD = 24;
|
||||
public final static int CLOUDY = 25;
|
||||
public final static int MOSTLY_CLOUDY_NIGHT = 26;
|
||||
public final static int MOSTLY_CLOUDY_DAY = 27;
|
||||
public final static int PARTLY_CLOUDY_NIGHT = 28;
|
||||
public final static int PARTLY_CLOUDY_DAY = 29;
|
||||
public final static int CLEAR_NIGHT = 30;
|
||||
public final static int SUNNY = 31;
|
||||
public final static int FAIR_NIGHT = 32;
|
||||
public final static int FAIR_DAY = 33;
|
||||
public final static int MIXED_RAIN_AND_HAIL = 34;
|
||||
public final static int HOT = 35;
|
||||
public final static int ISOLATED_THUNDERSTORMS = 36;
|
||||
public final static int SCATTERED_THUNDERSTORMS = 37;
|
||||
public final static int SCATTERED_SHOWERS = 38;
|
||||
public final static int HEAVY_SNOW = 39;
|
||||
public final static int SCATTERED_SNOW_SHOWERS = 40;
|
||||
public final static int PARTLY_CLOUDY = 41;
|
||||
public final static int THUNDERSHOWER = 42;
|
||||
public final static int SNOW_SHOWERS = 43;
|
||||
public final static int ISOLATED_THUNDERSHOWERS = 44;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final static int WEATHER_CODE_MAX = 44;
|
||||
|
||||
public final static int NOT_AVAILABLE = 3200;
|
||||
}
|
||||
}
|
||||
}
|
435
app/src/main/java/lineageos/weather/LineageWeatherManager.java
Normal file
435
app/src/main/java/lineageos/weather/LineageWeatherManager.java
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import lineageos.app.LineageContextConstants;
|
||||
import lineageos.providers.WeatherContract;
|
||||
|
||||
/**
|
||||
* Provides access to the weather services in the device.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public class LineageWeatherManager {
|
||||
|
||||
private static ILineageWeatherManager sWeatherManagerService;
|
||||
private static LineageWeatherManager sInstance;
|
||||
private Context mContext;
|
||||
private Map<RequestInfo,WeatherUpdateRequestListener> mWeatherUpdateRequestListeners
|
||||
= Collections.synchronizedMap(new HashMap<RequestInfo,WeatherUpdateRequestListener>());
|
||||
private Map<RequestInfo,LookupCityRequestListener> mLookupNameRequestListeners
|
||||
= Collections.synchronizedMap(new HashMap<RequestInfo,LookupCityRequestListener>());
|
||||
private Handler mHandler;
|
||||
private Set<WeatherServiceProviderChangeListener> mProviderChangedListeners = new ArraySet<>();
|
||||
|
||||
private static final String TAG = LineageWeatherManager.class.getSimpleName();
|
||||
|
||||
|
||||
/**
|
||||
* The different request statuses
|
||||
*/
|
||||
public static final class RequestStatus {
|
||||
|
||||
private 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 is 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 LineageWeatherManager(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
mContext = (appContext != null) ? appContext : context;
|
||||
sWeatherManagerService = getService();
|
||||
|
||||
if (context.getPackageManager().hasSystemFeature(
|
||||
LineageContextConstants.Features.WEATHER_SERVICES) && (sWeatherManagerService == null)) {
|
||||
Log.wtf(TAG, "Unable to bind the LineageWeatherManagerService");
|
||||
}
|
||||
mHandler = new Handler(appContext.getMainLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates an instance of the {@link lineageos.weather.LineageWeatherManager}
|
||||
* @param context
|
||||
* @return {@link LineageWeatherManager}
|
||||
*/
|
||||
public static LineageWeatherManager getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new LineageWeatherManager(context);
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@SuppressLint("PrivateApi")
|
||||
public static ILineageWeatherManager getService() {
|
||||
if (sWeatherManagerService != null) {
|
||||
return sWeatherManagerService;
|
||||
}
|
||||
|
||||
// This is a Gadgetbridge hack
|
||||
IBinder binder = null;
|
||||
try {
|
||||
Class localClass = Class.forName("android.os.ServiceManager");
|
||||
Method getService = localClass.getMethod("getService", String.class);
|
||||
Object result = getService.invoke(localClass, LineageContextConstants.LINEAGE_WEATHER_SERVICE);
|
||||
if (result != null) {
|
||||
binder = (IBinder) result;
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (binder != null) {
|
||||
sWeatherManagerService = ILineageWeatherManager.Stub.asInterface(binder);
|
||||
return sWeatherManagerService;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the weather service to request the latest available weather information for
|
||||
* the supplied {@link android.location.Location} location.
|
||||
*
|
||||
* @param location The location you want to get the latest weather data from.
|
||||
* @param listener {@link WeatherUpdateRequestListener} To be notified once the active weather
|
||||
* service provider has finished
|
||||
* processing your request
|
||||
* @return An integer that identifies the request submitted to the weather service
|
||||
* Note that this method might return -1 if an error occurred while trying to submit
|
||||
* the request.
|
||||
*/
|
||||
public int requestWeatherUpdate(@NonNull Location location,
|
||||
@NonNull WeatherUpdateRequestListener listener) {
|
||||
if (sWeatherManagerService == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
int tempUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS;
|
||||
|
||||
RequestInfo info = new RequestInfo
|
||||
.Builder(mRequestInfoListener)
|
||||
.setLocation(location)
|
||||
.setTemperatureUnit(tempUnit)
|
||||
.build();
|
||||
if (listener != null) mWeatherUpdateRequestListeners.put(info, listener);
|
||||
sWeatherManagerService.updateWeather(info);
|
||||
return info.hashCode();
|
||||
} catch (RemoteException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the weather service to request the latest weather information for the provided
|
||||
* WeatherLocation. This is the preferred method for requesting a weather update.
|
||||
*
|
||||
* @param weatherLocation A {@link lineageos.weather.WeatherLocation} that was previously
|
||||
* obtained by calling
|
||||
* {@link #lookupCity(String, LookupCityRequestListener)}
|
||||
* @param listener {@link WeatherUpdateRequestListener} To be notified once the active weather
|
||||
* service provider has finished
|
||||
* processing your request
|
||||
* @return An integer that identifies the request submitted to the weather service.
|
||||
* Note that this method might return -1 if an error occurred while trying to submit
|
||||
* the request.
|
||||
*/
|
||||
public int requestWeatherUpdate(@NonNull WeatherLocation weatherLocation,
|
||||
@NonNull WeatherUpdateRequestListener listener) {
|
||||
if (sWeatherManagerService == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
int tempUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS;
|
||||
|
||||
RequestInfo info = new RequestInfo
|
||||
.Builder(mRequestInfoListener)
|
||||
.setWeatherLocation(weatherLocation)
|
||||
.setTemperatureUnit(tempUnit)
|
||||
.build();
|
||||
if (listener != null) mWeatherUpdateRequestListeners.put(info, listener);
|
||||
sWeatherManagerService.updateWeather(info);
|
||||
return info.hashCode();
|
||||
} catch (RemoteException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the active weather provider service to lookup the supplied city name.
|
||||
*
|
||||
* @param city The city name
|
||||
* @param listener {@link LookupCityRequestListener} To be notified once the request has been
|
||||
* completed. Upon success, a list of
|
||||
* {@link lineageos.weather.WeatherLocation}
|
||||
* will be provided
|
||||
* @return An integer that identifies the request submitted to the weather service.
|
||||
* Note that this method might return -1 if an error occurred while trying to submit
|
||||
* the request.
|
||||
*/
|
||||
public int lookupCity(@NonNull String city, @NonNull LookupCityRequestListener listener) {
|
||||
if (sWeatherManagerService == null) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
RequestInfo info = new RequestInfo
|
||||
.Builder(mRequestInfoListener)
|
||||
.setCityName(city)
|
||||
.build();
|
||||
if (listener != null) mLookupNameRequestListeners.put(info, listener);
|
||||
sWeatherManagerService.lookupCity(info);
|
||||
return info.hashCode();
|
||||
} catch (RemoteException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a request that was previously submitted to the weather service.
|
||||
* @param requestId The ID that you received when the request was submitted
|
||||
*/
|
||||
public void cancelRequest(int requestId) {
|
||||
if (sWeatherManagerService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
sWeatherManagerService.cancelRequest(requestId);
|
||||
}catch (RemoteException e){
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link WeatherServiceProviderChangeListener} to be notified when a new weather
|
||||
* service provider becomes active.
|
||||
* @param listener {@link WeatherServiceProviderChangeListener} to register
|
||||
*/
|
||||
public void registerWeatherServiceProviderChangeListener(
|
||||
@NonNull WeatherServiceProviderChangeListener listener) {
|
||||
if (sWeatherManagerService == null) return;
|
||||
|
||||
synchronized (mProviderChangedListeners) {
|
||||
if (mProviderChangedListeners.contains(listener)) {
|
||||
throw new IllegalArgumentException("Listener already registered");
|
||||
}
|
||||
if (mProviderChangedListeners.size() == 0) {
|
||||
try {
|
||||
sWeatherManagerService.registerWeatherServiceProviderChangeListener(
|
||||
mProviderChangeListener);
|
||||
} catch (RemoteException e){
|
||||
}
|
||||
}
|
||||
mProviderChangedListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a listener
|
||||
* @param listener A previously registered {@link WeatherServiceProviderChangeListener}
|
||||
*/
|
||||
public void unregisterWeatherServiceProviderChangeListener(
|
||||
@NonNull WeatherServiceProviderChangeListener listener) {
|
||||
if (sWeatherManagerService == null) return;
|
||||
|
||||
synchronized (mProviderChangedListeners) {
|
||||
if (!mProviderChangedListeners.contains(listener)) {
|
||||
throw new IllegalArgumentException("Listener was never registered");
|
||||
}
|
||||
mProviderChangedListeners.remove(listener);
|
||||
if (mProviderChangedListeners.size() == 0) {
|
||||
try {
|
||||
sWeatherManagerService.unregisterWeatherServiceProviderChangeListener(
|
||||
mProviderChangeListener);
|
||||
} catch(RemoteException e){
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service's label as declared by the active weather service provider in its manifest
|
||||
* @return the service's label
|
||||
*/
|
||||
public String getActiveWeatherServiceProviderLabel() {
|
||||
if (sWeatherManagerService == null) return null;
|
||||
|
||||
try {
|
||||
return sWeatherManagerService.getActiveWeatherServiceProviderLabel();
|
||||
} catch(RemoteException e){
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final IWeatherServiceProviderChangeListener mProviderChangeListener =
|
||||
new IWeatherServiceProviderChangeListener.Stub() {
|
||||
@Override
|
||||
public void onWeatherServiceProviderChanged(final String providerName) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mProviderChangedListeners) {
|
||||
List<WeatherServiceProviderChangeListener> deadListeners
|
||||
= new ArrayList<>();
|
||||
for (WeatherServiceProviderChangeListener listener
|
||||
: mProviderChangedListeners) {
|
||||
try {
|
||||
listener.onWeatherServiceProviderChanged(providerName);
|
||||
} catch (Throwable e) {
|
||||
deadListeners.add(listener);
|
||||
}
|
||||
}
|
||||
if (deadListeners.size() > 0) {
|
||||
for (WeatherServiceProviderChangeListener listener : deadListeners) {
|
||||
mProviderChangedListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private final IRequestInfoListener mRequestInfoListener = new IRequestInfoListener.Stub() {
|
||||
|
||||
@Override
|
||||
public void onWeatherRequestCompleted(final RequestInfo requestInfo, final int status,
|
||||
final WeatherInfo weatherInfo) {
|
||||
final WeatherUpdateRequestListener listener
|
||||
= mWeatherUpdateRequestListeners.remove(requestInfo);
|
||||
if (listener != null) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onWeatherRequestCompleted(status, weatherInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLookupCityRequestCompleted(RequestInfo requestInfo, final int status,
|
||||
final List<WeatherLocation> weatherLocations) {
|
||||
|
||||
final LookupCityRequestListener listener
|
||||
= mLookupNameRequestListeners.remove(requestInfo);
|
||||
if (listener != null) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onLookupCityRequestCompleted(status, weatherLocations);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface used to receive notifications upon completion of a weather update request
|
||||
*/
|
||||
public interface WeatherUpdateRequestListener {
|
||||
/**
|
||||
* This method will be called when the weather service provider has finished processing the
|
||||
* request
|
||||
*
|
||||
* @param status See {@link RequestStatus}
|
||||
*
|
||||
* @param weatherInfo A fully populated {@link WeatherInfo} if state is
|
||||
* {@link RequestStatus#COMPLETED}, null otherwise
|
||||
*/
|
||||
void onWeatherRequestCompleted(int status, WeatherInfo weatherInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to receive notifications upon completion of a request to lookup a city name
|
||||
*/
|
||||
public interface LookupCityRequestListener {
|
||||
/**
|
||||
* This method will be called when the weather service provider has finished processing the
|
||||
* request.
|
||||
*
|
||||
* @param status See {@link RequestStatus}
|
||||
*
|
||||
* @param locations A list of {@link WeatherLocation} if the status is
|
||||
* {@link RequestStatus#COMPLETED}, null otherwise
|
||||
*/
|
||||
void onLookupCityRequestCompleted(int status, List<WeatherLocation> locations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to be notified when the user changes the weather service provider
|
||||
*/
|
||||
public interface WeatherServiceProviderChangeListener {
|
||||
/**
|
||||
* This method will be called when a new weather service provider becomes active in the
|
||||
* system. The parameter can be null when
|
||||
* <p>The user removed the active weather service provider from the system </p>
|
||||
* <p>The active weather provider was disabled.</p>
|
||||
*
|
||||
* @param providerLabel The label as declared on the weather service provider manifest
|
||||
*/
|
||||
void onWeatherServiceProviderChanged(String providerLabel);
|
||||
}
|
||||
}
|
379
app/src/main/java/lineageos/weather/RequestInfo.java
Normal file
379
app/src/main/java/lineageos/weather/RequestInfo.java
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import lineageos.os.Build;
|
||||
import lineageos.os.Concierge;
|
||||
import lineageos.os.Concierge.ParcelInfo;
|
||||
import lineageos.providers.WeatherContract;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class holds the information of a request submitted to the active weather provider service
|
||||
*/
|
||||
public final class RequestInfo implements Parcelable {
|
||||
|
||||
private Location mLocation;
|
||||
private String mCityName;
|
||||
private WeatherLocation mWeatherLocation;
|
||||
private int mRequestType;
|
||||
private IRequestInfoListener mListener;
|
||||
private int mTempUnit;
|
||||
private String mKey;
|
||||
private boolean mIsQueryOnly;
|
||||
|
||||
/**
|
||||
* A request to update the weather data using a geographical {@link android.location.Location}
|
||||
*/
|
||||
public static final int TYPE_WEATHER_BY_GEO_LOCATION_REQ = 1;
|
||||
/**
|
||||
* A request to update the weather data using a {@link WeatherLocation}
|
||||
*/
|
||||
public static final int TYPE_WEATHER_BY_WEATHER_LOCATION_REQ = 2;
|
||||
|
||||
/**
|
||||
* A request to look up a city name
|
||||
*/
|
||||
public static final int TYPE_LOOKUP_CITY_NAME_REQ = 3;
|
||||
|
||||
private RequestInfo() {}
|
||||
|
||||
/* package */ static class Builder {
|
||||
private Location mLocation;
|
||||
private String mCityName;
|
||||
private WeatherLocation mWeatherLocation;
|
||||
private int mRequestType;
|
||||
private IRequestInfoListener mListener;
|
||||
private int mTempUnit = WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT;
|
||||
private boolean mIsQueryOnly = false;
|
||||
|
||||
public Builder(IRequestInfoListener listener) {
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the city name and identifies this request as a {@link #TYPE_LOOKUP_CITY_NAME_REQ}
|
||||
* request. If set, will null out the location and weather location. Attempting to set
|
||||
* a null city name will get you an IllegalArgumentException
|
||||
*/
|
||||
public Builder setCityName(String cityName) {
|
||||
if (cityName == null) {
|
||||
throw new IllegalArgumentException("City name can't be null");
|
||||
}
|
||||
this.mCityName = cityName;
|
||||
this.mRequestType = TYPE_LOOKUP_CITY_NAME_REQ;
|
||||
this.mLocation = null;
|
||||
this.mWeatherLocation = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Location and identifies this request as a
|
||||
* {@link #TYPE_WEATHER_BY_GEO_LOCATION_REQ}. If set, will null out the city name and
|
||||
* weather location. Attempting to set a null location will get you an
|
||||
* IllegalArgumentException
|
||||
*/
|
||||
public Builder setLocation(Location location) {
|
||||
if (location == null) {
|
||||
throw new IllegalArgumentException("Location can't be null");
|
||||
}
|
||||
this.mLocation = new Location(location);
|
||||
this.mCityName = null;
|
||||
this.mWeatherLocation = null;
|
||||
this.mRequestType = TYPE_WEATHER_BY_GEO_LOCATION_REQ;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the weather location and identifies this request as a
|
||||
* {@link #TYPE_WEATHER_BY_WEATHER_LOCATION_REQ}. If set, will null out the location and
|
||||
* city name. Attempting to set a null weather location will get you an
|
||||
* IllegalArgumentException
|
||||
*/
|
||||
public Builder setWeatherLocation(WeatherLocation weatherLocation) {
|
||||
if (weatherLocation == null) {
|
||||
throw new IllegalArgumentException("WeatherLocation can't be null");
|
||||
}
|
||||
this.mWeatherLocation = weatherLocation;
|
||||
this.mLocation = null;
|
||||
this.mCityName = null;
|
||||
this.mRequestType = TYPE_WEATHER_BY_WEATHER_LOCATION_REQ;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unit in which the temperature will be reported if the request is honored.
|
||||
* Valid values are:
|
||||
* <ul>
|
||||
* {@link lineageos.providers.WeatherContract.WeatherColumns.TempUnit#CELSIUS}
|
||||
* {@link lineageos.providers.WeatherContract.WeatherColumns.TempUnit#FAHRENHEIT}
|
||||
* </ul>
|
||||
* Any other value will generate an IllegalArgumentException. If the temperature unit is not
|
||||
* set, the default will be degrees Fahrenheit
|
||||
* @param unit A valid temperature unit
|
||||
*/
|
||||
public Builder setTemperatureUnit(int unit) {
|
||||
if (!isValidTempUnit(unit)) {
|
||||
throw new IllegalArgumentException("Invalid temperature unit");
|
||||
}
|
||||
this.mTempUnit = unit;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a weather request, marks the request as a query only, meaning that the
|
||||
* content provider won't be updated after the active weather service has finished
|
||||
* processing the request.
|
||||
*/
|
||||
public Builder queryOnly() {
|
||||
switch (mRequestType) {
|
||||
case TYPE_WEATHER_BY_GEO_LOCATION_REQ:
|
||||
case TYPE_WEATHER_BY_WEATHER_LOCATION_REQ:
|
||||
this.mIsQueryOnly = true;
|
||||
break;
|
||||
default:
|
||||
this.mIsQueryOnly = false;
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine all of the options that have been set and return a new {@link RequestInfo} object
|
||||
* @return {@link RequestInfo}
|
||||
*/
|
||||
public RequestInfo build() {
|
||||
RequestInfo info = new RequestInfo();
|
||||
info.mListener = this.mListener;
|
||||
info.mRequestType = this.mRequestType;
|
||||
info.mCityName = this.mCityName;
|
||||
info.mWeatherLocation = this.mWeatherLocation;
|
||||
info.mLocation = this.mLocation;
|
||||
info.mTempUnit = this.mTempUnit;
|
||||
info.mIsQueryOnly = this.mIsQueryOnly;
|
||||
info.mKey = UUID.randomUUID().toString();
|
||||
return info;
|
||||
}
|
||||
|
||||
private boolean isValidTempUnit(int unit) {
|
||||
switch (unit) {
|
||||
case WeatherContract.WeatherColumns.TempUnit.CELSIUS:
|
||||
case WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private RequestInfo(Parcel parcel) {
|
||||
// Read parcelable version via the Concierge
|
||||
ParcelInfo parcelInfo = Concierge.receiveParcel(parcel);
|
||||
int parcelableVersion = parcelInfo.getParcelVersion();
|
||||
|
||||
if (parcelableVersion >= Build.LINEAGE_VERSION_CODES.ELDERBERRY) {
|
||||
mKey = parcel.readString();
|
||||
mRequestType = parcel.readInt();
|
||||
switch (mRequestType) {
|
||||
case TYPE_WEATHER_BY_GEO_LOCATION_REQ:
|
||||
mLocation = Location.CREATOR.createFromParcel(parcel);
|
||||
mTempUnit = parcel.readInt();
|
||||
break;
|
||||
case TYPE_WEATHER_BY_WEATHER_LOCATION_REQ:
|
||||
mWeatherLocation = WeatherLocation.CREATOR.createFromParcel(parcel);
|
||||
mTempUnit = parcel.readInt();
|
||||
break;
|
||||
case TYPE_LOOKUP_CITY_NAME_REQ:
|
||||
mCityName = parcel.readString();
|
||||
break;
|
||||
}
|
||||
mIsQueryOnly = (parcel.readInt() == 1);
|
||||
mListener = IRequestInfoListener.Stub.asInterface(parcel.readStrongBinder());
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The request type
|
||||
*/
|
||||
public int getRequestType() {
|
||||
return mRequestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link android.location.Location} if this is a request by location, null
|
||||
* otherwise
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return new Location(mLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link lineageos.weather.WeatherLocation} if this is a request by weather
|
||||
* location, null otherwise
|
||||
*/
|
||||
public WeatherLocation getWeatherLocation() {
|
||||
return mWeatherLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public IRequestInfoListener getRequestListener() {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the city name if this is a lookup request, null otherwise
|
||||
*/
|
||||
public String getCityName() {
|
||||
return mCityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the temperature unit if this is a weather request, -1 otherwise
|
||||
*/
|
||||
public int getTemperatureUnit() {
|
||||
switch (mRequestType) {
|
||||
case TYPE_WEATHER_BY_GEO_LOCATION_REQ:
|
||||
case TYPE_WEATHER_BY_WEATHER_LOCATION_REQ:
|
||||
return mTempUnit;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if this is a weather request, whether the request will update the content provider.
|
||||
* False for other kind of requests
|
||||
* @hide
|
||||
*/
|
||||
public boolean isQueryOnlyWeatherRequest() {
|
||||
switch (mRequestType) {
|
||||
case TYPE_WEATHER_BY_GEO_LOCATION_REQ:
|
||||
case TYPE_WEATHER_BY_WEATHER_LOCATION_REQ:
|
||||
return mIsQueryOnly;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator<RequestInfo> CREATOR = new Creator<RequestInfo>() {
|
||||
@Override
|
||||
public RequestInfo createFromParcel(Parcel in) {
|
||||
return new RequestInfo(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestInfo[] newArray(int size) {
|
||||
return new RequestInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Tell the concierge to prepare the parcel
|
||||
ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
|
||||
|
||||
// ==== ELDERBERRY =====
|
||||
dest.writeString(mKey);
|
||||
dest.writeInt(mRequestType);
|
||||
switch (mRequestType) {
|
||||
case TYPE_WEATHER_BY_GEO_LOCATION_REQ:
|
||||
mLocation.writeToParcel(dest, 0);
|
||||
dest.writeInt(mTempUnit);
|
||||
break;
|
||||
case TYPE_WEATHER_BY_WEATHER_LOCATION_REQ:
|
||||
mWeatherLocation.writeToParcel(dest, 0);
|
||||
dest.writeInt(mTempUnit);
|
||||
break;
|
||||
case TYPE_LOOKUP_CITY_NAME_REQ:
|
||||
dest.writeString(mCityName);
|
||||
break;
|
||||
}
|
||||
dest.writeInt(mIsQueryOnly == true ? 1 : 0);
|
||||
dest.writeStrongBinder(mListener.asBinder());
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("{ Request for ");
|
||||
switch (mRequestType) {
|
||||
case TYPE_WEATHER_BY_GEO_LOCATION_REQ:
|
||||
builder.append("Location: ").append(mLocation);
|
||||
builder.append(" Temp Unit: ");
|
||||
if (mTempUnit == WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT) {
|
||||
builder.append("Fahrenheit");
|
||||
} else {
|
||||
builder.append(" Celsius");
|
||||
}
|
||||
break;
|
||||
case TYPE_WEATHER_BY_WEATHER_LOCATION_REQ:
|
||||
builder.append("WeatherLocation: ").append(mWeatherLocation);
|
||||
builder.append(" Temp Unit: ");
|
||||
if (mTempUnit == WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT) {
|
||||
builder.append("Fahrenheit");
|
||||
} else {
|
||||
builder.append(" Celsius");
|
||||
}
|
||||
break;
|
||||
case TYPE_LOOKUP_CITY_NAME_REQ:
|
||||
builder.append("Lookup City: ").append(mCityName);
|
||||
break;
|
||||
}
|
||||
return builder.append(" }").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((mKey != null) ? mKey.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
|
||||
if (getClass() == obj.getClass()) {
|
||||
RequestInfo info = (RequestInfo) obj;
|
||||
return (TextUtils.equals(mKey, info.mKey));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
642
app/src/main/java/lineageos/weather/WeatherInfo.java
Executable file
642
app/src/main/java/lineageos/weather/WeatherInfo.java
Executable file
@ -0,0 +1,642 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanongenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import lineageos.os.Build;
|
||||
import lineageos.os.Concierge;
|
||||
import lineageos.os.Concierge.ParcelInfo;
|
||||
import lineageos.providers.WeatherContract;
|
||||
import lineageos.weatherservice.ServiceRequest;
|
||||
import lineageos.weatherservice.ServiceRequestResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class represents the weather information that a
|
||||
* {@link lineageos.weatherservice.WeatherProviderService} will use to update the weather content
|
||||
* provider. A weather provider service will be called by the system to process an update
|
||||
* request at any time. If the service successfully processes the request, then the weather provider
|
||||
* service is responsible of calling
|
||||
* {@link ServiceRequest#complete(ServiceRequestResult)} to notify the
|
||||
* system that the request was completed and that the weather content provider should be updated
|
||||
* with the supplied weather information.
|
||||
*/
|
||||
public final class WeatherInfo implements Parcelable {
|
||||
|
||||
private String mCity;
|
||||
private int mConditionCode;
|
||||
private double mTemperature;
|
||||
private int mTempUnit;
|
||||
private double mTodaysHighTemp;
|
||||
private double mTodaysLowTemp;
|
||||
private double mHumidity;
|
||||
private double mWindSpeed;
|
||||
private double mWindDirection;
|
||||
private int mWindSpeedUnit;
|
||||
private long mTimestamp;
|
||||
private List<DayForecast> mForecastList;
|
||||
private String mKey;
|
||||
|
||||
private WeatherInfo() {}
|
||||
|
||||
/**
|
||||
* Builder class for {@link WeatherInfo}
|
||||
*/
|
||||
public static class Builder {
|
||||
private String mCity;
|
||||
private int mConditionCode = WeatherContract.WeatherColumns.WeatherCode.NOT_AVAILABLE;
|
||||
private double mTemperature;
|
||||
private int mTempUnit;
|
||||
private double mTodaysHighTemp = Double.NaN;
|
||||
private double mTodaysLowTemp = Double.NaN;
|
||||
private double mHumidity = Double.NaN;
|
||||
private double mWindSpeed = Double.NaN;
|
||||
private double mWindDirection = Double.NaN;
|
||||
private int mWindSpeedUnit = WeatherContract.WeatherColumns.WindSpeedUnit.MPH;
|
||||
private long mTimestamp = -1;
|
||||
private List<DayForecast> mForecastList = new ArrayList<>(0);
|
||||
|
||||
/**
|
||||
* @param cityName A valid city name. Attempting to pass null will get you an
|
||||
* IllegalArgumentException
|
||||
* @param temperature A valid temperature value. Attempting pass an invalid double value,
|
||||
* will get you an IllegalArgumentException
|
||||
* @param tempUnit A valid temperature unit value. See
|
||||
* {@link lineageos.providers.WeatherContract.WeatherColumns.TempUnit} for
|
||||
* valid values. Attempting to pass an invalid temperature unit will get you
|
||||
* an IllegalArgumentException
|
||||
*/
|
||||
public Builder(@NonNull String cityName, double temperature, int tempUnit) {
|
||||
if (cityName == null) {
|
||||
throw new IllegalArgumentException("City name can't be null");
|
||||
}
|
||||
if (Double.isNaN(temperature)) {
|
||||
throw new IllegalArgumentException("Invalid temperature");
|
||||
}
|
||||
if (!isValidTempUnit(tempUnit)) {
|
||||
throw new IllegalArgumentException("Invalid temperature unit");
|
||||
}
|
||||
this.mCity = cityName;
|
||||
this.mTemperature = temperature;
|
||||
this.mTempUnit = tempUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeStamp A timestamp indicating when this data was generated. If timestamps is
|
||||
* not set, then the builder will set it to the time of object creation
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setTimestamp(long timeStamp) {
|
||||
mTimestamp = timeStamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param humidity The weather humidity. Attempting to pass an invalid double value will get
|
||||
* you an IllegalArgumentException
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setHumidity(double humidity) {
|
||||
if (Double.isNaN(humidity)) {
|
||||
throw new IllegalArgumentException("Invalid humidity value");
|
||||
}
|
||||
|
||||
mHumidity = humidity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param windSpeed The wind speed. Attempting to pass an invalid double value will get you
|
||||
* an IllegalArgumentException
|
||||
* @param windDirection The wind direction. Attempting to pass an invalid double value will
|
||||
* get you an IllegalArgumentException
|
||||
* @param windSpeedUnit A valid wind speed direction unit. See
|
||||
* {@link lineageos.providers.WeatherContract.WeatherColumns.WindSpeedUnit}
|
||||
* for valid values. Attempting to pass an invalid speed unit will get
|
||||
* you an IllegalArgumentException
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setWind(double windSpeed, double windDirection, int windSpeedUnit) {
|
||||
if (Double.isNaN(windSpeed)) {
|
||||
throw new IllegalArgumentException("Invalid wind speed value");
|
||||
}
|
||||
if (Double.isNaN(windDirection)) {
|
||||
throw new IllegalArgumentException("Invalid wind direction value");
|
||||
}
|
||||
if (!isValidWindSpeedUnit(windSpeedUnit)) {
|
||||
throw new IllegalArgumentException("Invalid speed unit");
|
||||
}
|
||||
mWindSpeed = windSpeed;
|
||||
mWindSpeedUnit = windSpeedUnit;
|
||||
mWindDirection = windDirection;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param conditionCode A valid weather condition code. See
|
||||
* {@link lineageos.providers.WeatherContract.WeatherColumns.WeatherCode}
|
||||
* for valid codes. Attempting to pass an invalid code will get you an
|
||||
* IllegalArgumentException.
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setWeatherCondition(int conditionCode) {
|
||||
if (!isValidWeatherCode(conditionCode)) {
|
||||
throw new IllegalArgumentException("Invalid weather condition code");
|
||||
}
|
||||
mConditionCode = conditionCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forecasts A valid array list of {@link DayForecast} objects. Attempting to pass
|
||||
* null will get you an IllegalArgumentException'
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setForecast(@NonNull List<DayForecast> forecasts) {
|
||||
if (forecasts == null) {
|
||||
throw new IllegalArgumentException("Forecast list can't be null");
|
||||
}
|
||||
mForecastList = forecasts;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param todaysHigh Today's high temperature. Attempting to pass an invalid double value
|
||||
* will get you an IllegalArgumentException
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setTodaysHigh(double todaysHigh) {
|
||||
if (Double.isNaN(todaysHigh)) {
|
||||
throw new IllegalArgumentException("Invalid temperature value");
|
||||
}
|
||||
mTodaysHighTemp = todaysHigh;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param todaysLow Today's low temperature. Attempting to pass an invalid double value will
|
||||
* get you an IllegalArgumentException
|
||||
* @return
|
||||
*/
|
||||
public Builder setTodaysLow(double todaysLow) {
|
||||
if (Double.isNaN(todaysLow)) {
|
||||
throw new IllegalArgumentException("Invalid temperature value");
|
||||
}
|
||||
mTodaysLowTemp = todaysLow;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine all of the options that have been set and return a new {@link WeatherInfo} object
|
||||
* @return {@link WeatherInfo}
|
||||
*/
|
||||
public WeatherInfo build() {
|
||||
WeatherInfo info = new WeatherInfo();
|
||||
info.mCity = this.mCity;
|
||||
info.mConditionCode = this.mConditionCode;
|
||||
info.mTemperature = this.mTemperature;
|
||||
info.mTempUnit = this.mTempUnit;
|
||||
info.mHumidity = this.mHumidity;
|
||||
info.mWindSpeed = this.mWindSpeed;
|
||||
info.mWindDirection = this.mWindDirection;
|
||||
info.mWindSpeedUnit = this.mWindSpeedUnit;
|
||||
info.mTimestamp = this.mTimestamp == -1 ? System.currentTimeMillis() : this.mTimestamp;
|
||||
info.mForecastList = this.mForecastList;
|
||||
info.mTodaysHighTemp = this.mTodaysHighTemp;
|
||||
info.mTodaysLowTemp = this.mTodaysLowTemp;
|
||||
info.mKey = UUID.randomUUID().toString();
|
||||
return info;
|
||||
}
|
||||
|
||||
private boolean isValidTempUnit(int unit) {
|
||||
switch (unit) {
|
||||
case WeatherContract.WeatherColumns.TempUnit.CELSIUS:
|
||||
case WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidWindSpeedUnit(int unit) {
|
||||
switch (unit) {
|
||||
case WeatherContract.WeatherColumns.WindSpeedUnit.KPH:
|
||||
case WeatherContract.WeatherColumns.WindSpeedUnit.MPH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean isValidWeatherCode(int code) {
|
||||
if (code < WeatherContract.WeatherColumns.WeatherCode.WEATHER_CODE_MIN
|
||||
|| code > WeatherContract.WeatherColumns.WeatherCode.WEATHER_CODE_MAX) {
|
||||
if (code != WeatherContract.WeatherColumns.WeatherCode.NOT_AVAILABLE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return city name
|
||||
*/
|
||||
public String getCity() {
|
||||
return mCity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An implementation specific weather condition code
|
||||
*/
|
||||
public int getConditionCode() {
|
||||
return mConditionCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return humidity
|
||||
*/
|
||||
public double getHumidity() {
|
||||
return mHumidity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return time stamp when the request was processed
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return wind direction (degrees)
|
||||
*/
|
||||
public double getWindDirection() {
|
||||
return mWindDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return wind speed
|
||||
*/
|
||||
public double getWindSpeed() {
|
||||
return mWindSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return wind speed unit
|
||||
*/
|
||||
public int getWindSpeedUnit() {
|
||||
return mWindSpeedUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current temperature
|
||||
*/
|
||||
public double getTemperature() {
|
||||
return mTemperature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return temperature unit
|
||||
*/
|
||||
public int getTemperatureUnit() {
|
||||
return mTempUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return today's high temperature
|
||||
*/
|
||||
public double getTodaysHigh() {
|
||||
return mTodaysHighTemp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return today's low temperature
|
||||
*/
|
||||
public double getTodaysLow() {
|
||||
return mTodaysLowTemp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of {@link lineageos.weather.WeatherInfo.DayForecast}. This list will contain
|
||||
* the forecast weather for the upcoming days. If you want to know today's high and low
|
||||
* temperatures, use {@link WeatherInfo#getTodaysHigh()} and {@link WeatherInfo#getTodaysLow()}
|
||||
*/
|
||||
public List<DayForecast> getForecasts() {
|
||||
return new ArrayList<>(mForecastList);
|
||||
}
|
||||
|
||||
private WeatherInfo(Parcel parcel) {
|
||||
// Read parcelable version via the Concierge
|
||||
ParcelInfo parcelInfo = Concierge.receiveParcel(parcel);
|
||||
int parcelableVersion = parcelInfo.getParcelVersion();
|
||||
|
||||
if (parcelableVersion >= Build.LINEAGE_VERSION_CODES.ELDERBERRY) {
|
||||
mKey = parcel.readString();
|
||||
mCity = parcel.readString();
|
||||
mConditionCode = parcel.readInt();
|
||||
mTemperature = parcel.readDouble();
|
||||
mTempUnit = parcel.readInt();
|
||||
mHumidity = parcel.readDouble();
|
||||
mWindSpeed = parcel.readDouble();
|
||||
mWindDirection = parcel.readDouble();
|
||||
mWindSpeedUnit = parcel.readInt();
|
||||
mTodaysHighTemp = parcel.readDouble();
|
||||
mTodaysLowTemp = parcel.readDouble();
|
||||
mTimestamp = parcel.readLong();
|
||||
int forecastListSize = parcel.readInt();
|
||||
mForecastList = new ArrayList<>();
|
||||
while (forecastListSize > 0) {
|
||||
mForecastList.add(DayForecast.CREATOR.createFromParcel(parcel));
|
||||
forecastListSize--;
|
||||
}
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Tell the concierge to prepare the parcel
|
||||
ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
|
||||
|
||||
// ==== ELDERBERRY =====
|
||||
dest.writeString(mKey);
|
||||
dest.writeString(mCity);
|
||||
dest.writeInt(mConditionCode);
|
||||
dest.writeDouble(mTemperature);
|
||||
dest.writeInt(mTempUnit);
|
||||
dest.writeDouble(mHumidity);
|
||||
dest.writeDouble(mWindSpeed);
|
||||
dest.writeDouble(mWindDirection);
|
||||
dest.writeInt(mWindSpeedUnit);
|
||||
dest.writeDouble(mTodaysHighTemp);
|
||||
dest.writeDouble(mTodaysLowTemp);
|
||||
dest.writeLong(mTimestamp);
|
||||
dest.writeInt(mForecastList.size());
|
||||
for (DayForecast dayForecast : mForecastList) {
|
||||
dayForecast.writeToParcel(dest, 0);
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<WeatherInfo> CREATOR =
|
||||
new Parcelable.Creator<WeatherInfo>() {
|
||||
|
||||
@Override
|
||||
public WeatherInfo createFromParcel(Parcel source) {
|
||||
return new WeatherInfo(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeatherInfo[] newArray(int size) {
|
||||
return new WeatherInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents the weather forecast for a given day. Do not add low and high
|
||||
* temperatures for the current day in this list. Use
|
||||
* {@link WeatherInfo.Builder#setTodaysHigh(double)} and
|
||||
* {@link WeatherInfo.Builder#setTodaysLow(double)} instead.
|
||||
*/
|
||||
public static class DayForecast implements Parcelable{
|
||||
double mLow;
|
||||
double mHigh;
|
||||
int mConditionCode;
|
||||
String mKey;
|
||||
|
||||
private DayForecast() {}
|
||||
|
||||
/**
|
||||
* Builder class for {@link DayForecast}
|
||||
*/
|
||||
public static class Builder {
|
||||
double mLow = Double.NaN;
|
||||
double mHigh = Double.NaN;
|
||||
int mConditionCode;
|
||||
|
||||
/**
|
||||
* @param conditionCode A valid weather condition code. See
|
||||
* {@link lineageos.providers.WeatherContract.WeatherColumns.WeatherCode} for valid
|
||||
* values. Attempting to pass an invalid code will get you an
|
||||
* IllegalArgumentException
|
||||
*/
|
||||
public Builder(int conditionCode) {
|
||||
if (!isValidWeatherCode(conditionCode)) {
|
||||
throw new IllegalArgumentException("Invalid weather condition code");
|
||||
}
|
||||
mConditionCode = conditionCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param high Forecast high temperature for this day. Attempting to pass an invalid
|
||||
* double value will get you an IllegalArgumentException
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setHigh(double high) {
|
||||
if (Double.isNaN(high)) {
|
||||
throw new IllegalArgumentException("Invalid high forecast temperature");
|
||||
}
|
||||
mHigh = high;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param low Forecast low temperate for this day. Attempting to pass an invalid double
|
||||
* value will get you an IllegalArgumentException
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setLow(double low) {
|
||||
if (Double.isNaN(low)) {
|
||||
throw new IllegalArgumentException("Invalid low forecast temperature");
|
||||
}
|
||||
mLow = low;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Combine all of the options that have been set and return a new {@link DayForecast}
|
||||
* object
|
||||
* @return {@link DayForecast}
|
||||
*/
|
||||
public DayForecast build() {
|
||||
DayForecast forecast = new DayForecast();
|
||||
forecast.mLow = this.mLow;
|
||||
forecast.mHigh = this.mHigh;
|
||||
forecast.mConditionCode = this.mConditionCode;
|
||||
forecast.mKey = UUID.randomUUID().toString();
|
||||
return forecast;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return forecasted low temperature
|
||||
*/
|
||||
public double getLow() {
|
||||
return mLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return not what you think. Returns the forecasted high temperature
|
||||
*/
|
||||
public double getHigh() {
|
||||
return mHigh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return forecasted weather condition code. Implementation specific
|
||||
*/
|
||||
public int getConditionCode() {
|
||||
return mConditionCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Tell the concierge to prepare the parcel
|
||||
ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
|
||||
|
||||
// ==== ELDERBERRY =====
|
||||
dest.writeString(mKey);
|
||||
dest.writeDouble(mLow);
|
||||
dest.writeDouble(mHigh);
|
||||
dest.writeInt(mConditionCode);
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<DayForecast> CREATOR =
|
||||
new Parcelable.Creator<DayForecast>() {
|
||||
@Override
|
||||
public DayForecast createFromParcel(Parcel source) {
|
||||
return new DayForecast(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DayForecast[] newArray(int size) {
|
||||
return new DayForecast[size];
|
||||
}
|
||||
};
|
||||
|
||||
private DayForecast(Parcel parcel) {
|
||||
// Read parcelable version via the Concierge
|
||||
ParcelInfo parcelInfo = Concierge.receiveParcel(parcel);
|
||||
int parcelableVersion = parcelInfo.getParcelVersion();
|
||||
|
||||
if (parcelableVersion >= Build.LINEAGE_VERSION_CODES.ELDERBERRY) {
|
||||
mKey = parcel.readString();
|
||||
mLow = parcel.readDouble();
|
||||
mHigh = parcel.readDouble();
|
||||
mConditionCode = parcel.readInt();
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("{Low temp: ").append(mLow)
|
||||
.append(" High temp: ").append(mHigh)
|
||||
.append(" Condition code: ").append(mConditionCode)
|
||||
.append("}").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((mKey != null) ? mKey.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
|
||||
if (getClass() == obj.getClass()) {
|
||||
DayForecast forecast = (DayForecast) obj;
|
||||
return (TextUtils.equals(mKey, forecast.mKey));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder()
|
||||
.append(" City Name: ").append(mCity)
|
||||
.append(" Condition Code: ").append(mConditionCode)
|
||||
.append(" Temperature: ").append(mTemperature)
|
||||
.append(" Temperature Unit: ").append(mTempUnit)
|
||||
.append(" Humidity: ").append(mHumidity)
|
||||
.append(" Wind speed: ").append(mWindSpeed)
|
||||
.append(" Wind direction: ").append(mWindDirection)
|
||||
.append(" Wind Speed Unit: ").append(mWindSpeedUnit)
|
||||
.append(" Today's high temp: ").append(mTodaysHighTemp)
|
||||
.append(" Today's low temp: ").append(mTodaysLowTemp)
|
||||
.append(" Timestamp: ").append(mTimestamp).append(" Forecasts: [");
|
||||
for (DayForecast dayForecast : mForecastList) {
|
||||
builder.append(dayForecast.toString());
|
||||
}
|
||||
return builder.append("]}").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((mKey != null) ? mKey.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
|
||||
if (getClass() == obj.getClass()) {
|
||||
WeatherInfo info = (WeatherInfo) obj;
|
||||
return (TextUtils.equals(mKey, info.mKey));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
274
app/src/main/java/lineageos/weather/WeatherLocation.java
Normal file
274
app/src/main/java/lineageos/weather/WeatherLocation.java
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import lineageos.os.Build;
|
||||
import lineageos.os.Concierge;
|
||||
import lineageos.os.Concierge.ParcelInfo;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A class representing a geographical location that a weather service provider can use to
|
||||
* get weather data from. Each service provider will potentially populate objects of this class
|
||||
* with different content, so make sure you don't preserve the values when a service provider
|
||||
* is changed
|
||||
*/
|
||||
public final class WeatherLocation implements Parcelable{
|
||||
private String mCityId;
|
||||
private String mCity;
|
||||
private String mState;
|
||||
private String mPostal;
|
||||
private String mCountryId;
|
||||
private String mCountry;
|
||||
private String mKey;
|
||||
|
||||
private WeatherLocation() {}
|
||||
|
||||
/**
|
||||
* Builder class for {@link WeatherLocation}
|
||||
*/
|
||||
public static class Builder {
|
||||
String mCityId = "";
|
||||
String mCity = "";
|
||||
String mState = "";
|
||||
String mPostal = "";
|
||||
String mCountryId = "";
|
||||
String mCountry = "";
|
||||
|
||||
/**
|
||||
* @param cityId An identifier for the city (for example WOEID - Where On Earth IDentifier)
|
||||
* @param cityName The name of the city
|
||||
*/
|
||||
public Builder(String cityId, String cityName) {
|
||||
if (cityId == null || cityName == null) {
|
||||
throw new IllegalArgumentException("Illegal to set city id AND city to null");
|
||||
}
|
||||
this.mCityId = cityId;
|
||||
this.mCity = cityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cityName The name of the city
|
||||
*/
|
||||
public Builder(String cityName) {
|
||||
if (cityName == null) {
|
||||
throw new IllegalArgumentException("City name can't be null");
|
||||
}
|
||||
this.mCity = cityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param countryId An identifier for the country (for example ISO alpha-2, ISO alpha-3,
|
||||
* ISO 3166-1 numeric-3, etc)
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setCountryId(String countryId) {
|
||||
if (countryId == null) {
|
||||
throw new IllegalArgumentException("Country ID can't be null");
|
||||
}
|
||||
this.mCountryId = countryId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param country The country name
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setCountry(String country) {
|
||||
if (country == null) {
|
||||
throw new IllegalArgumentException("Country can't be null");
|
||||
}
|
||||
this.mCountry = country;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param postalCode The postal/ZIP code
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setPostalCode(String postalCode) {
|
||||
if (postalCode == null) {
|
||||
throw new IllegalArgumentException("Postal code/ZIP can't be null");
|
||||
}
|
||||
this.mPostal = postalCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param state The state or territory where the city is located
|
||||
* @return The {@link Builder} instance
|
||||
*/
|
||||
public Builder setState(String state) {
|
||||
if (state == null) {
|
||||
throw new IllegalArgumentException("State can't be null");
|
||||
}
|
||||
this.mState = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine all of the options that have been set and return a new {@link WeatherLocation}
|
||||
* object
|
||||
* @return {@link WeatherLocation}
|
||||
*/
|
||||
public WeatherLocation build() {
|
||||
WeatherLocation weatherLocation = new WeatherLocation();
|
||||
weatherLocation.mCityId = this.mCityId;
|
||||
weatherLocation.mCity = this.mCity;
|
||||
weatherLocation.mState = this.mState;
|
||||
weatherLocation.mPostal = this.mPostal;
|
||||
weatherLocation.mCountryId = this.mCountryId;
|
||||
weatherLocation.mCountry = this.mCountry;
|
||||
weatherLocation.mKey = UUID.randomUUID().toString();
|
||||
return weatherLocation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The city ID. This method will return an empty string if the city ID was not set
|
||||
*/
|
||||
public String getCityId() {
|
||||
return mCityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The city name. This method will return an empty string if the city name was not set
|
||||
*/
|
||||
public String getCity() {
|
||||
return mCity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The state name. This method will return an empty string if the state was not set
|
||||
*/
|
||||
public String getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The postal/ZIP code. This method will return an empty string if the postal/ZIP code
|
||||
* was not set
|
||||
*/
|
||||
public String getPostalCode() {
|
||||
return mPostal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The country ID. This method will return an empty string if the country ID was not set
|
||||
*/
|
||||
public String getCountryId() {
|
||||
return mCountryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The country name. This method will return an empty string if the country ID was not
|
||||
* set
|
||||
*/
|
||||
public String getCountry() {
|
||||
return mCountry;
|
||||
}
|
||||
|
||||
private WeatherLocation(Parcel in) {
|
||||
// Read parcelable version via the Concierge
|
||||
ParcelInfo parcelInfo = Concierge.receiveParcel(in);
|
||||
int parcelableVersion = parcelInfo.getParcelVersion();
|
||||
|
||||
if (parcelableVersion >= Build.LINEAGE_VERSION_CODES.ELDERBERRY) {
|
||||
mKey = in.readString();
|
||||
mCityId = in.readString();
|
||||
mCity = in.readString();
|
||||
mState = in.readString();
|
||||
mPostal = in.readString();
|
||||
mCountryId = in.readString();
|
||||
mCountry = in.readString();
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
public static final Creator<WeatherLocation> CREATOR = new Creator<WeatherLocation>() {
|
||||
@Override
|
||||
public WeatherLocation createFromParcel(Parcel in) {
|
||||
return new WeatherLocation(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeatherLocation[] newArray(int size) {
|
||||
return new WeatherLocation[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Tell the concierge to prepare the parcel
|
||||
ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
|
||||
|
||||
// ==== ELDERBERRY =====
|
||||
dest.writeString(mKey);
|
||||
dest.writeString(mCityId);
|
||||
dest.writeString(mCity);
|
||||
dest.writeString(mState);
|
||||
dest.writeString(mPostal);
|
||||
dest.writeString(mCountryId);
|
||||
dest.writeString(mCountry);
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("{ City ID: ").append(mCityId)
|
||||
.append(" City: ").append(mCity)
|
||||
.append(" State: ").append(mState)
|
||||
.append(" Postal/ZIP Code: ").append(mPostal)
|
||||
.append(" Country Id: ").append(mCountryId)
|
||||
.append(" Country: ").append(mCountry).append("}")
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((mKey != null) ? mKey.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
|
||||
if (getClass() == obj.getClass()) {
|
||||
WeatherLocation location = (WeatherLocation) obj;
|
||||
return (TextUtils.equals(mKey, location.mKey));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
84
app/src/main/java/lineageos/weather/util/WeatherUtils.java
Normal file
84
app/src/main/java/lineageos/weather/util/WeatherUtils.java
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weather.util;
|
||||
|
||||
|
||||
import lineageos.providers.WeatherContract;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
* Helper class to perform operations and formatting of weather data
|
||||
*/
|
||||
public class WeatherUtils {
|
||||
|
||||
/**
|
||||
* Converts a temperature expressed in degrees Celsius to degrees Fahrenheit
|
||||
* @param celsius temperature in Celsius
|
||||
* @return the temperature in degrees Fahrenheit
|
||||
*/
|
||||
public static double celsiusToFahrenheit(double celsius) {
|
||||
return ((celsius * (9d/5d)) + 32d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a temperature expressed in degrees Fahrenheit to degrees Celsius
|
||||
* @param fahrenheit temperature in Fahrenheit
|
||||
* @return the temperature in degrees Celsius
|
||||
*/
|
||||
public static double fahrenheitToCelsius(double fahrenheit) {
|
||||
return ((fahrenheit - 32d) * (5d/9d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the temperature and unit supplied. The temperature value
|
||||
* will be half-even rounded.
|
||||
* @param temperature the temperature value
|
||||
* @param tempUnit A valid {@link WeatherContract.WeatherColumns.TempUnit}
|
||||
* @return A string with the format XX°F or XX°C (where XX is the temperature)
|
||||
* depending on the temperature unit that was provided or null if an invalid unit is supplied
|
||||
*/
|
||||
public static String formatTemperature(double temperature, int tempUnit) {
|
||||
if (!isValidTempUnit(tempUnit)) return null;
|
||||
if (Double.isNaN(temperature)) return "-";
|
||||
|
||||
DecimalFormat noDigitsFormat = new DecimalFormat("0");
|
||||
String noDigitsTemp = noDigitsFormat.format(temperature);
|
||||
if (noDigitsTemp.equals("-0")) {
|
||||
noDigitsTemp = "0";
|
||||
}
|
||||
|
||||
StringBuilder formatted = new StringBuilder()
|
||||
.append(noDigitsTemp).append("\u00b0");
|
||||
if (tempUnit == WeatherContract.WeatherColumns.TempUnit.CELSIUS) {
|
||||
formatted.append("C");
|
||||
} else if (tempUnit == WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT) {
|
||||
formatted.append("F");
|
||||
}
|
||||
return formatted.toString();
|
||||
}
|
||||
|
||||
private static boolean isValidTempUnit(int unit) {
|
||||
switch (unit) {
|
||||
case WeatherContract.WeatherColumns.TempUnit.CELSIUS:
|
||||
case WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
161
app/src/main/java/lineageos/weatherservice/ServiceRequest.java
Normal file
161
app/src/main/java/lineageos/weatherservice/ServiceRequest.java
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weatherservice;
|
||||
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import lineageos.weatherservice.IWeatherProviderServiceClient;
|
||||
import lineageos.weather.LineageWeatherManager;
|
||||
import lineageos.weather.RequestInfo;
|
||||
|
||||
/**
|
||||
* This class represents a request submitted by the system to the active weather provider service
|
||||
*/
|
||||
public final class ServiceRequest {
|
||||
|
||||
private final RequestInfo mInfo;
|
||||
private final IWeatherProviderServiceClient mClient;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the request information
|
||||
* @return {@link lineageos.weather.RequestInfo}
|
||||
*/
|
||||
public RequestInfo getRequestInfo() {
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called once the request has been completed
|
||||
*/
|
||||
public void complete(@NonNull ServiceRequestResult result) {
|
||||
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,
|
||||
LineageWeatherManager.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,
|
||||
LineageWeatherManager.RequestStatus.NO_MATCH_FOUND);
|
||||
} else {
|
||||
mClient.setServiceRequestState(mInfo, result,
|
||||
LineageWeatherManager.RequestStatus.COMPLETED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
mStatus = Status.COMPLETED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called if the service failed to process the request
|
||||
* (no internet connection, time out, etc.)
|
||||
*/
|
||||
public void fail() {
|
||||
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,
|
||||
LineageWeatherManager.RequestStatus.FAILED);
|
||||
break;
|
||||
case RequestInfo.TYPE_LOOKUP_CITY_NAME_REQ:
|
||||
mClient.setServiceRequestState(mInfo, null,
|
||||
LineageWeatherManager.RequestStatus.FAILED);
|
||||
break;
|
||||
}
|
||||
} 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.
|
||||
* <ul>
|
||||
* <li>{@link lineageos.weather.LineageWeatherManager.RequestStatus#SUBMITTED_TOO_SOON}</li>
|
||||
* <li>{@link lineageos.weather.LineageWeatherManager.RequestStatus#ALREADY_IN_PROGRESS}</li>
|
||||
* </ul>
|
||||
* 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 LineageWeatherManager.RequestStatus.ALREADY_IN_PROGRESS:
|
||||
case LineageWeatherManager.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the WeatherProviderService base class to notify we don't want this request anymore.
|
||||
* The service implementing the WeatherProviderService will be notified of this action
|
||||
* via onRequestCancelled()
|
||||
* @hide
|
||||
*/
|
||||
public void cancel() {
|
||||
synchronized (this) {
|
||||
mStatus = Status.CANCELLED;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weatherservice;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import lineageos.os.Build;
|
||||
import lineageos.os.Concierge;
|
||||
import lineageos.os.Concierge.ParcelInfo;
|
||||
import lineageos.weather.WeatherLocation;
|
||||
import lineageos.weather.WeatherInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Use this class to build a request result.
|
||||
*/
|
||||
public final class ServiceRequestResult implements Parcelable {
|
||||
|
||||
private WeatherInfo mWeatherInfo;
|
||||
private List<WeatherLocation> mLocationLookupList;
|
||||
private String mKey;
|
||||
|
||||
private ServiceRequestResult() {}
|
||||
|
||||
private ServiceRequestResult(Parcel in) {
|
||||
// Read parcelable version via the Concierge
|
||||
ParcelInfo parcelInfo = Concierge.receiveParcel(in);
|
||||
int parcelableVersion = parcelInfo.getParcelVersion();
|
||||
|
||||
if (parcelableVersion >= Build.LINEAGE_VERSION_CODES.ELDERBERRY) {
|
||||
mKey = in.readString();
|
||||
int hasWeatherInfo = in.readInt();
|
||||
if (hasWeatherInfo == 1) {
|
||||
mWeatherInfo = WeatherInfo.CREATOR.createFromParcel(in);
|
||||
}
|
||||
int hasLocationLookupList = in.readInt();
|
||||
if (hasLocationLookupList == 1) {
|
||||
mLocationLookupList = new ArrayList<>();
|
||||
int listSize = in.readInt();
|
||||
while (listSize > 0) {
|
||||
mLocationLookupList.add(WeatherLocation.CREATOR.createFromParcel(in));
|
||||
listSize--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
public static final Creator<ServiceRequestResult> CREATOR
|
||||
= new Creator<ServiceRequestResult>() {
|
||||
@Override
|
||||
public ServiceRequestResult createFromParcel(Parcel in) {
|
||||
return new ServiceRequestResult(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceRequestResult[] newArray(int size) {
|
||||
return new ServiceRequestResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Tell the concierge to prepare the parcel
|
||||
ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
|
||||
|
||||
// ==== ELDERBERRY =====
|
||||
dest.writeString(mKey);
|
||||
if (mWeatherInfo != null) {
|
||||
dest.writeInt(1);
|
||||
mWeatherInfo.writeToParcel(dest, 0);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
if (mLocationLookupList != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeInt(mLocationLookupList.size());
|
||||
for (WeatherLocation lookup : mLocationLookupList) {
|
||||
lookup.writeToParcel(dest, 0);
|
||||
}
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link ServiceRequestResult}
|
||||
*/
|
||||
public static class Builder {
|
||||
private WeatherInfo mWeatherInfo;
|
||||
private List<WeatherLocation> mLocationLookupList;
|
||||
public Builder() {
|
||||
this.mWeatherInfo = null;
|
||||
this.mLocationLookupList = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param weatherInfo The WeatherInfo object holding the data that will be used to update
|
||||
* the weather content provider
|
||||
*/
|
||||
public Builder(@NonNull WeatherInfo weatherInfo) {
|
||||
if (weatherInfo == null) {
|
||||
throw new IllegalArgumentException("WeatherInfo can't be null");
|
||||
}
|
||||
|
||||
mWeatherInfo = weatherInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param locations The list of WeatherLocation objects. The list should not be null
|
||||
*/
|
||||
public Builder(@NonNull List<WeatherLocation> locations) {
|
||||
if (locations == null) {
|
||||
throw new IllegalArgumentException("Weather location list can't be null");
|
||||
}
|
||||
mLocationLookupList = locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ServiceRequestResult} with the arguments
|
||||
* supplied to this builder
|
||||
* @return {@link ServiceRequestResult}
|
||||
*/
|
||||
public ServiceRequestResult build() {
|
||||
ServiceRequestResult result = new ServiceRequestResult();
|
||||
result.mWeatherInfo = this.mWeatherInfo;
|
||||
result.mLocationLookupList = this.mLocationLookupList;
|
||||
result.mKey = UUID.randomUUID().toString();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The WeatherInfo object supplied by the weather provider service
|
||||
*/
|
||||
public WeatherInfo getWeatherInfo() {
|
||||
return mWeatherInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The list of WeatherLocation objects supplied by the weather provider service
|
||||
*/
|
||||
public List<WeatherLocation> getLocationLookupList() {
|
||||
return new ArrayList<>(mLocationLookupList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((mKey != null) ? mKey.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
|
||||
if (getClass() == obj.getClass()) {
|
||||
ServiceRequestResult request = (ServiceRequestResult) obj;
|
||||
return (TextUtils.equals(mKey, request.mKey));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package lineageos.weatherservice;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import lineageos.weather.RequestInfo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
|
||||
public abstract class WeatherProviderService extends Service {
|
||||
|
||||
private Handler mHandler;
|
||||
private IWeatherProviderServiceClient mClient;
|
||||
private Set<ServiceRequest> mWeakRequestsSet
|
||||
= Collections.newSetFromMap(new WeakHashMap<ServiceRequest, Boolean>());
|
||||
|
||||
/**
|
||||
* The {@link android.content.Intent} action that must be declared as handled by a service in
|
||||
* its manifest for the system to recognize it as a weather provider service
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE
|
||||
= "lineageos.weatherservice.WeatherProviderService";
|
||||
|
||||
/**
|
||||
* Name under which a {@link WeatherProviderService} publishes information about itself.
|
||||
* This meta-data must reference an XML resource containing
|
||||
* a <code><weather-provider-service></code>
|
||||
* tag.
|
||||
*/
|
||||
public static final String SERVICE_META_DATA = "lineageos.weatherservice";
|
||||
|
||||
@Override
|
||||
protected final void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
mHandler = new ServiceHandler(base.getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
private final IWeatherProviderService.Stub mBinder = new IWeatherProviderService.Stub() {
|
||||
|
||||
@Override
|
||||
public void processWeatherUpdateRequest(final RequestInfo info) {
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_ON_NEW_REQUEST, info).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processCityNameLookupRequest(final RequestInfo info) {
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_ON_NEW_REQUEST, info).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServiceClient(IWeatherProviderServiceClient client) {
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_SET_CLIENT, client).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelOngoingRequests() {
|
||||
synchronized (mWeakRequestsSet) {
|
||||
for (final ServiceRequest request : mWeakRequestsSet) {
|
||||
request.cancel();
|
||||
mWeakRequestsSet.remove(request);
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_CANCEL_REQUEST, request)
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelRequest(int requestId) {
|
||||
synchronized (mWeakRequestsSet) {
|
||||
for (final ServiceRequest request : mWeakRequestsSet) {
|
||||
if (request.getRequestInfo().hashCode() == requestId) {
|
||||
mWeakRequestsSet.remove(request);
|
||||
request.cancel();
|
||||
mHandler.obtainMessage(ServiceHandler.MSG_CANCEL_REQUEST, request)
|
||||
.sendToTarget();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private class ServiceHandler extends Handler {
|
||||
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
public static final int MSG_SET_CLIENT = 1;
|
||||
public static final int MSG_ON_NEW_REQUEST = 2;
|
||||
public static final int MSG_CANCEL_REQUEST = 3;
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_SET_CLIENT: {
|
||||
mClient = (IWeatherProviderServiceClient) msg.obj;
|
||||
if (mClient != null) {
|
||||
onConnected();
|
||||
} else {
|
||||
onDisconnected();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case MSG_ON_NEW_REQUEST: {
|
||||
RequestInfo info = (RequestInfo) msg.obj;
|
||||
if (info != null) {
|
||||
ServiceRequest request = new ServiceRequest(info, mClient);
|
||||
synchronized (mWeakRequestsSet) {
|
||||
mWeakRequestsSet.add(request);
|
||||
}
|
||||
onRequestSubmitted(request);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case MSG_CANCEL_REQUEST: {
|
||||
ServiceRequest request = (ServiceRequest) msg.obj;
|
||||
onRequestCancelled(request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The system has connected to this service.
|
||||
*/
|
||||
protected void onConnected() {
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* The system has disconnected from this service.
|
||||
*/
|
||||
protected void onDisconnected() {
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* A new request has been submitted to this service
|
||||
* @param request The service request to be processed by this service
|
||||
*/
|
||||
protected abstract void onRequestSubmitted(ServiceRequest request);
|
||||
|
||||
/**
|
||||
* Called when the system is not interested on this request anymore. Note that the service
|
||||
* <b>has marked the request as cancelled</b> and you must stop any ongoing operation
|
||||
* (such as pulling data from internet) that this service could've been performing to honor the
|
||||
* request.
|
||||
*
|
||||
* @param request The request cancelled by the system
|
||||
*/
|
||||
protected abstract void onRequestCancelled(ServiceRequest request);
|
||||
}
|
Loading…
Reference in New Issue
Block a user