├── .gitignore
├── LICENSE
├── MobileWeather
├── .gitignore
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── sdl
│ │ │ └── mobileweather
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── ic_launcher-web.png
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── sdl
│ │ │ │ └── mobileweather
│ │ │ │ ├── activity
│ │ │ │ └── MainActivity.java
│ │ │ │ ├── adapter
│ │ │ │ └── ForecastListAdapter.java
│ │ │ │ ├── artifact
│ │ │ │ ├── Const.java
│ │ │ │ ├── GPSLocation.java
│ │ │ │ └── WeatherLocation.java
│ │ │ │ ├── connection
│ │ │ │ └── HttpConnection.java
│ │ │ │ ├── fragments
│ │ │ │ ├── AlertsFragment.java
│ │ │ │ ├── BaseFragment.java
│ │ │ │ ├── ConditionsFragment.java
│ │ │ │ └── ForecastFragment.java
│ │ │ │ ├── localization
│ │ │ │ └── LocalizationUtil.java
│ │ │ │ ├── location
│ │ │ │ ├── LocationJsonProcessor.java
│ │ │ │ ├── PlayServicesConnectionChecker.java
│ │ │ │ └── WeatherLocationServices.java
│ │ │ │ ├── openweathermap
│ │ │ │ ├── OpenWeatherMapLocationJsonProcessor.java
│ │ │ │ ├── OpenWeatherMapService.java
│ │ │ │ └── OpenWeatherMapWeatherJsonProcessor.java
│ │ │ │ ├── processor
│ │ │ │ ├── ImageProcessor.java
│ │ │ │ └── JsonProcessor.java
│ │ │ │ ├── smartdevicelink
│ │ │ │ ├── SdlActivity.java
│ │ │ │ ├── SdlApplication.java
│ │ │ │ ├── SdlReceiver.java
│ │ │ │ ├── SdlRouterService.java
│ │ │ │ └── SdlService.java
│ │ │ │ └── weather
│ │ │ │ ├── AbbreviationDictionary.java
│ │ │ │ ├── Forecast.java
│ │ │ │ ├── InfoType.java
│ │ │ │ ├── RoadConditions.java
│ │ │ │ ├── UnitConverter.java
│ │ │ │ ├── WeatherAlarmManager.java
│ │ │ │ ├── WeatherAlert.java
│ │ │ │ ├── WeatherAlertType.java
│ │ │ │ ├── WeatherConditions.java
│ │ │ │ ├── WeatherDataManager.java
│ │ │ │ ├── WeatherJsonProcessor.java
│ │ │ │ ├── WeatherService.java
│ │ │ │ └── WeatherUpdateWakefulReceiver.java
│ │ └── res
│ │ │ ├── drawable-hdpi
│ │ │ ├── chancesnow.png
│ │ │ ├── chancesnow_50.png
│ │ │ ├── chancestorm.png
│ │ │ ├── chancestorm_50.png
│ │ │ ├── chancethunderstorm.png
│ │ │ ├── chancethunderstorm_50.png
│ │ │ ├── clearday.png
│ │ │ ├── clearday_50.png
│ │ │ ├── clearnight.png
│ │ │ ├── clearnight_50.png
│ │ │ ├── cloudy.png
│ │ │ ├── cloudy_50.png
│ │ │ ├── dusk.png
│ │ │ ├── dusk_50.png
│ │ │ ├── fog.png
│ │ │ ├── fog_50.png
│ │ │ ├── fogcloudy.png
│ │ │ ├── fogcloudy_50.png
│ │ │ ├── fognight.png
│ │ │ ├── fognight_50.png
│ │ │ ├── ford_oval.png
│ │ │ ├── hazy.png
│ │ │ ├── hazy_50.png
│ │ │ ├── ic_drawer.png
│ │ │ ├── icon_license.xml
│ │ │ ├── lightrain.png
│ │ │ ├── lightrain_50.png
│ │ │ ├── lightsnow.png
│ │ │ ├── lightsnow_50.png
│ │ │ ├── partlycloudyday.png
│ │ │ ├── partlycloudyday_50.png
│ │ │ ├── partlycloudynight.png
│ │ │ ├── partlycloudynight_50.png
│ │ │ ├── partlysunny.png
│ │ │ ├── partlysunny_50.png
│ │ │ ├── powered.png
│ │ │ ├── rain.png
│ │ │ ├── rain_50.png
│ │ │ ├── sleet.png
│ │ │ ├── sleet_50.png
│ │ │ ├── snow.png
│ │ │ ├── snow_50.png
│ │ │ ├── snowflake.png
│ │ │ ├── snowflake_50.png
│ │ │ ├── storm.png
│ │ │ ├── storm_50.png
│ │ │ ├── sunrise.png
│ │ │ ├── sunrise_50.png
│ │ │ ├── thunderstorm.png
│ │ │ ├── thunderstorm_50.png
│ │ │ ├── windy.png
│ │ │ ├── windy_50.png
│ │ │ ├── windycloudy.png
│ │ │ ├── windycloudy_50.png
│ │ │ ├── windyrain.png
│ │ │ ├── windyrain_50.png
│ │ │ └── wunderground.png
│ │ │ ├── drawable-mdpi
│ │ │ ├── ic_add_location.png
│ │ │ ├── ic_current_location.png
│ │ │ └── ic_settings.png
│ │ │ ├── drawable-xhdpi
│ │ │ ├── ic_add_location.png
│ │ │ ├── ic_current_location.png
│ │ │ └── ic_settings.png
│ │ │ ├── drawable-xxhdpi
│ │ │ ├── ic_add_location.png
│ │ │ ├── ic_current_location.png
│ │ │ ├── ic_settings.png
│ │ │ └── icon.png
│ │ │ ├── drawable
│ │ │ ├── ic_01d.png
│ │ │ ├── ic_01n.png
│ │ │ ├── ic_02d.png
│ │ │ ├── ic_02n.png
│ │ │ ├── ic_03d.png
│ │ │ ├── ic_03n.png
│ │ │ ├── ic_04d.png
│ │ │ ├── ic_04n.png
│ │ │ ├── ic_09d.png
│ │ │ ├── ic_09n.png
│ │ │ ├── ic_10d.png
│ │ │ ├── ic_10n.png
│ │ │ ├── ic_11d.png
│ │ │ ├── ic_11n.png
│ │ │ ├── ic_13d.png
│ │ │ ├── ic_13n.png
│ │ │ ├── ic_50d.png
│ │ │ ├── ic_50n.png
│ │ │ └── ic_none.png
│ │ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ ├── drawer_list_item.xml
│ │ │ ├── forecast_list_item.xml
│ │ │ ├── fragment_alerts.xml
│ │ │ ├── fragment_base.xml
│ │ │ ├── fragment_conditions.xml
│ │ │ ├── fragment_forecast.xml
│ │ │ └── lockscreen.xml
│ │ │ ├── menu
│ │ │ ├── alerts.xml
│ │ │ └── forecast.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── values-de
│ │ │ └── strings.xml
│ │ │ ├── values-es-rES
│ │ │ └── strings.xml
│ │ │ ├── values-es-rMX
│ │ │ └── strings.xml
│ │ │ ├── values-large
│ │ │ └── dimens.xml
│ │ │ ├── values-pt-rBR
│ │ │ └── strings.xml
│ │ │ ├── values-pt-rPT
│ │ │ └── strings.xml
│ │ │ ├── values-sw600dp
│ │ │ └── dimens.xml
│ │ │ ├── values-sw720dp-land
│ │ │ └── dimens.xml
│ │ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ └── weather_abrv.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── sdl
│ │ └── mobileweather
│ │ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ompiled source #
2 | ###################
3 | *.com
4 | *.class
5 | *.dll
6 | *.exe
7 | *.o
8 | *.so
9 |
10 | # Packages #
11 | ############
12 | # it's better to unpack these files and commit the raw source
13 | # git has its own built in compression methods
14 | *.7z
15 | *.dmg
16 | *.gz
17 | *.iso
18 | *.jar
19 | *.rar
20 | *.tar
21 | *.zip
22 |
23 | # Logs and databases #
24 | ######################
25 | *.log
26 | *.sql
27 | *.sqlite
28 |
29 | # OS generated files #
30 | ######################
31 | .DS_Store
32 | .DS_Store?
33 | ._*
34 | .Spotlight-V100
35 | .Trashes
36 | Icon?
37 | ehthumbs.db
38 | Thumbs.db
39 |
40 | ########Android Auto Generate##########
41 | bin/
42 | gen/
43 | /bin
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 - 2018 SmartDeviceLink Consortium, Inc.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of SmartDeviceLink Consortium, Inc. nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/MobileWeather/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | /.idea/misc.xml
8 | /.idea/jarRepositories.xml
9 | /.idea/gradle.xml
10 | /.idea/compiler.xml
11 | /.idea/vcs.xml
12 | /.idea/caches/build_file_checksums.ser
13 | .DS_Store
14 | /build
15 | /captures
16 | .externalNativeBuild
17 |
--------------------------------------------------------------------------------
/MobileWeather/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/MobileWeather/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 34
5 | defaultConfig {
6 | applicationId "com.sdl.mobileweather"
7 | minSdkVersion 16
8 | targetSdkVersion 34
9 | versionCode 28
10 | versionName "1.7.15"
11 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | flavorDimensions "default"
20 | productFlavors{
21 | multi_sec_off {
22 | buildConfigField 'String', 'TRANSPORT', '"MULTI"'
23 | buildConfigField 'String', 'SECURITY', '"OFF"'
24 | }
25 | tcp {
26 | buildConfigField 'String', 'TRANSPORT', '"TCP"'
27 | buildConfigField 'String', 'SECURITY', '"OFF"'
28 | }
29 | }
30 | lintOptions {
31 | disable 'GoogleAppIndexingWarning'
32 | }
33 | }
34 |
35 | dependencies {
36 | implementation fileTree(dir: 'libs', include: ['*.jar'])
37 | testImplementation 'junit:junit:4.12'
38 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
39 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
40 | implementation 'com.smartdevicelink:sdl_android:5.7.0'
41 | implementation 'net.hockeyapp.android:HockeySDK:5.1.0'
42 | implementation 'com.google.android.gms:play-services-location:16.0.0'
43 | }
44 |
--------------------------------------------------------------------------------
/MobileWeather/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | -keep class com.smartdevicelink.** { *; }
16 | -keep class com.livio.** { *; }
17 |
18 | # Uncomment this to preserve the line number information for
19 | # debugging stack traces.
20 | #-keepattributes SourceFile,LineNumberTable
21 |
22 | # If you keep the line number information, uncomment this to
23 | # hide the original source file name.
24 | #-renamesourcefileattribute SourceFile
25 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/androidTest/java/com/sdl/mobileweather/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather;
2 |
3 | import android.content.Context;
4 | import androidx.test.platform.app.InstrumentationRegistry;
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | import com.sdl.mobileweather.openweathermap.OpenWeatherMapService;
13 |
14 | /**
15 | * Instrumented test, which will execute on an Android device.
16 | *
17 | * @see Testing documentation
18 | */
19 | @RunWith(AndroidJUnit4.class)
20 | public class ExampleInstrumentedTest {
21 | @Test
22 | public void useAppContext() {
23 | // Context of the app under test.
24 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
25 |
26 | assertEquals("com.sdl.mobileweather", appContext.getPackageName());
27 | }
28 |
29 |
30 | @Test
31 | public void openWeatherAPIRequestSuccessful() {
32 | OpenWeatherMapService openWeatherMapService = new OpenWeatherMapService();
33 | assertEquals(OpenWeatherMapService.REQUEST_SUCCESS, openWeatherMapService.getRequestStatus());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
11 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
41 |
42 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 |
71 |
72 |
73 |
78 |
79 |
83 |
84 |
85 |
86 |
89 |
90 |
91 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/adapter/ForecastListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.adapter;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.view.ViewGroup.LayoutParams;
10 | import android.widget.ArrayAdapter;
11 | import android.widget.ImageView;
12 | import android.widget.LinearLayout;
13 | import android.widget.TextView;
14 |
15 | import com.sdl.mobileweather.R;
16 | import com.sdl.mobileweather.processor.ImageProcessor;
17 | import com.sdl.mobileweather.weather.Forecast;
18 | import com.sdl.mobileweather.weather.UnitConverter;
19 | import com.sdl.mobileweather.weather.WeatherDataManager;
20 |
21 | import java.text.SimpleDateFormat;
22 | import java.util.Arrays;
23 | import java.util.Calendar;
24 | import java.util.Locale;
25 |
26 | public class ForecastListAdapter extends ArrayAdapter {
27 | private final Context mContext;
28 | private final Forecast[] mForecast;
29 | private WeatherDataManager mDataManager;
30 | private boolean[] mForecastType;
31 | private LayoutInflater mInflater;
32 | private Activity parentActivity;
33 |
34 | public ForecastListAdapter(Context context, Forecast[] forecast, Activity parentActivity) {
35 | super(context, R.layout.forecast_list_item, forecast);
36 | this.mContext = context;
37 | this.mForecast = forecast;
38 | this.mDataManager = WeatherDataManager.getInstance();
39 | this.mForecastType = new boolean[forecast.length];
40 | this.parentActivity = parentActivity;
41 | Arrays.fill(this.mForecastType, false);
42 | mInflater = ((Activity) this.mContext).getLayoutInflater();
43 | }
44 |
45 | public void toggleForecastType(int position) {
46 | if (position < this.mForecast.length) {
47 | this.mForecastType[position] = !this.mForecastType[position];
48 | }
49 | }
50 |
51 | @Override
52 | public View getView(int position, View view, ViewGroup parent) {
53 | View rowView;
54 |
55 | if (!this.mForecastType[position]) {
56 | rowView = mInflater.inflate(R.layout.forecast_list_item, null, true);
57 | ImageView forecastImageView = (ImageView) rowView.findViewById(R.id.forecastImageView);
58 | TextView shortDayTextView = (TextView) rowView.findViewById(R.id.forecastShortDayTextView);
59 | TextView precipTextView = (TextView) rowView.findViewById(R.id.forecastPrecip);
60 | TextView lowTempTextView = (TextView) rowView.findViewById(R.id.forecastLowTemp);
61 | TextView highTempTextView = (TextView) rowView.findViewById(R.id.forecastHighTemp);
62 |
63 | String units = null;
64 | if (mDataManager != null) {
65 | units = mDataManager.getUnits();
66 | }
67 |
68 | forecastImageView.setImageBitmap(null);
69 | shortDayTextView.setText("");
70 | precipTextView.setText("");
71 | lowTempTextView.setText("");
72 | highTempTextView.setText("");
73 |
74 | if (position < this.mForecast.length) {
75 | Forecast day = this.mForecast[position];
76 |
77 | if ((mContext.getResources().getString(R.string.conditions_loading)).equals(day.conditionTitle)) {
78 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
79 | precipTextView.setLayoutParams(params);
80 | precipTextView.setGravity(Gravity.CENTER | Gravity.CENTER);
81 | precipTextView.setText(day.conditionTitle);
82 | forecastImageView.setImageBitmap(null);
83 | }
84 | else if((day.conditionId != null) &&
85 | (day.precipitationChance != null) &&
86 | (day.highTemperature != null) &&
87 | (day.lowTemperature != null) &&
88 | (day.date != null)) {
89 | String conditionId = day.conditionId;
90 | Integer precip = day.precipitationChance;
91 | Float highTemperature = day.highTemperature;
92 | Float lowTemperature = day.lowTemperature;
93 | Calendar forecastDate = day.date;
94 |
95 | SimpleDateFormat dateFormat = new SimpleDateFormat(mContext.getResources().getString(R.string.weather_forecast_day_simpleDateFormat), Locale.getDefault());
96 | String dateString = dateFormat.format(forecastDate.getTime().getTime()*1000);
97 | String precipChance = null;
98 | String highTemp = null;
99 | String lowTemp = null;
100 |
101 | if ((mContext.getResources().getString(R.string.units_imperial)).equalsIgnoreCase(units) || units == null) {
102 | if (highTemperature != null)
103 | highTemperature = Float.valueOf(UnitConverter.convertTemperatureToImperial(highTemperature.floatValue()));
104 | if (lowTemperature != null)
105 | lowTemperature = Float.valueOf(UnitConverter.convertTemperatureToImperial(lowTemperature.floatValue()));
106 | }
107 | if (precip != null) {
108 | precipChance = String.format(Locale.getDefault(), "%d%%", precip.intValue());
109 | }
110 | else {
111 | precipChance = " ";
112 | }
113 | if (highTemperature != null)
114 | highTemp = String.format(Locale.getDefault(), mContext.getResources().getString(R.string.weather_forecast_high_temp) + "%.0f\u00B0", highTemperature);
115 | if (lowTemperature != null)
116 | lowTemp = String.format(Locale.getDefault(), mContext.getResources().getString(R.string.weather_forecast_low_temp) + "%.0f\u00B0", lowTemperature);
117 |
118 | shortDayTextView.setText(dateString);
119 | precipTextView.setText(precipChance);
120 | lowTempTextView.setText(lowTemp);
121 | highTempTextView.setText(highTemp);
122 | if (conditionId != null)
123 | ImageProcessor.setConditionsImage(forecastImageView, conditionId);
124 | }
125 | }
126 |
127 | }
128 | else {
129 | rowView = mInflater.inflate(R.layout.forecast_list_item, null, true);
130 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
131 | TextView precipTextView = (TextView) rowView.findViewById(R.id.forecastPrecip);
132 | ImageView forecastImageView = (ImageView) rowView.findViewById(R.id.forecastImageView);
133 | precipTextView.setLayoutParams(params);
134 | precipTextView.setGravity(Gravity.CENTER | Gravity.CENTER);
135 | precipTextView.setText(mContext.getResources().getString(R.string.weather_forecast_hourly));
136 | forecastImageView.setImageBitmap(null);
137 | }
138 | return rowView;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/artifact/Const.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.artifact;
2 |
3 | public class Const {
4 | public static final String PREFS_NAME = "MobileWeatherPrefs";
5 | }
6 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/artifact/GPSLocation.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.artifact;
2 |
3 | public class GPSLocation {
4 | public String latitude;
5 | public String longitude;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/artifact/WeatherLocation.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.artifact;
2 |
3 | public class WeatherLocation {
4 | public String state;
5 | public String city;
6 | public String zipCode;
7 | public String airportCode;
8 | public GPSLocation gpsLocation;
9 | }
10 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/connection/HttpConnection.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.connection;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.DataOutputStream;
5 | import java.io.IOException;
6 | import java.io.InputStreamReader;
7 | import java.net.HttpURLConnection;
8 | import java.net.ProtocolException;
9 | import java.net.URL;
10 | import java.util.Arrays;
11 | import java.util.List;
12 | import java.util.Locale;
13 |
14 | public class HttpConnection {
15 |
16 | public enum RequestMethod { GET, PUT, POST, DELETE };
17 | private static final Integer[] httpSuccessCodes = { 200, 201, 202, 203, 204, 205, 206, 207, 208, 226};
18 |
19 | /**
20 | * Returns the result of an HTTP request.
21 | *
22 | * @param url the request URL
23 | * @param requestMethod the type of HTTP request to perform
24 | * @param dataToSend the data to send to the server
25 | * @return the result of the request
26 | */
27 | public String sendRequest(URL url, RequestMethod requestMethod, String dataToSend, String contentType) {
28 | HttpURLConnection httpConnection = null;
29 |
30 | // Open the URL, send the request and any data, and read the result into a string
31 | try {
32 | // Open the connection
33 | httpConnection = (HttpURLConnection) url.openConnection();
34 | return performRequest(httpConnection, requestMethod, dataToSend, contentType);
35 | }
36 | catch (ProtocolException e) {
37 | e.printStackTrace();
38 | }
39 | catch (IOException e) {
40 | e.printStackTrace();
41 | } finally {
42 | if(httpConnection != null)
43 | httpConnection.disconnect();
44 | }
45 |
46 | return null;
47 | }
48 |
49 | /**
50 | * Performs an HTTP request.
51 | * @param httpConnection the HTTP connection.
52 | * @param requestMethod the HTTP RequestMethod.
53 | * @param dataToSend the data to send with the request, if any.
54 | * @param contentType the content type of the request.
55 | * @return the result of the request as a String.
56 | */
57 | private String performRequest(HttpURLConnection httpConnection, RequestMethod requestMethod, String dataToSend, String contentType) {
58 | BufferedReader httpBufferedReader = null;
59 | String currentLine = null;
60 | DataOutputStream postDataWriter = null;
61 | String httpData = "";
62 |
63 | // Open the URL, send the request and any data, and read the result into a string
64 | try {
65 | httpConnection.setRequestMethod(requestMethod.name());
66 | httpConnection.setDoInput(true);
67 |
68 | // For certain methods, we need to send data
69 | if ((requestMethod == RequestMethod.PUT || requestMethod == RequestMethod.POST) && (dataToSend != null)) {
70 | httpConnection.setDoOutput(true);
71 | httpConnection.setUseCaches(false);
72 | if (contentType != null) {
73 | httpConnection.setRequestProperty("Content-Type", contentType);
74 | }
75 | else {
76 | httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
77 | }
78 | httpConnection.setRequestProperty("Content-Language", "en-US");
79 | httpConnection.setRequestProperty("Content-Length", "" + Integer.toString(dataToSend.getBytes().length));
80 |
81 | postDataWriter = new DataOutputStream(httpConnection.getOutputStream());
82 | postDataWriter.writeBytes(dataToSend);
83 | postDataWriter.flush();
84 | postDataWriter.close();
85 | }
86 | else {
87 | httpConnection.setDoOutput(false);
88 | }
89 |
90 | // Get the HTTP response code
91 | int responseCode = httpConnection.getResponseCode();
92 |
93 | List codes = Arrays.asList(httpSuccessCodes);
94 | // If it doesn't equal 'OK' or we performed a DELETE, return the code and message
95 | if (!codes.contains(Integer.valueOf(responseCode)) || requestMethod == RequestMethod.DELETE) {
96 | httpData = String.format(Locale.getDefault(), "STATUS=%d:%s", responseCode, httpConnection.getResponseMessage());
97 | }
98 | else {
99 | // Get any output from the site
100 | httpBufferedReader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
101 | while ((currentLine = httpBufferedReader.readLine()) != null) {
102 | httpData += currentLine;
103 | }
104 | }
105 | }
106 | catch (ProtocolException e) {
107 | e.printStackTrace();
108 | }
109 | catch (IOException e) {
110 | e.printStackTrace();
111 | }
112 | catch (Exception e) {
113 | e.printStackTrace();
114 | }
115 | finally {
116 | if(httpConnection != null)
117 | httpConnection.disconnect();
118 | }
119 |
120 | return httpData;
121 | }
122 |
123 | /**
124 | * Checks for an HTTP error message from the sendRequest() method.
125 | * @param statusString the results of the request.
126 | * @return the HTTP error message, if any occurred.
127 | */
128 | public String getErrorMessage(String statusString) {
129 | if (statusString != null && statusString.startsWith("STATUS=")) {
130 | int separator = statusString.indexOf(":");
131 | if (separator > 0 && statusString.length() > separator) {
132 | return statusString.substring(separator + 1);
133 | }
134 | }
135 | return null;
136 | }
137 |
138 | /**
139 | * Converts an HTTP error message from the sendRequest() method
140 | * into the HTTP status code.
141 | *
142 | * @param statusString the results from the request.
143 | * @return the HTTP status code.
144 | */
145 | public int getStatusCode(String statusString) {
146 | if (statusString != null && statusString.startsWith("STATUS=")) {
147 | int separator = statusString.indexOf(":");
148 | if (separator > 0) {
149 | try {
150 | return Integer.parseInt(statusString.substring(7, separator));
151 | }
152 | catch (NumberFormatException e) {
153 | e.printStackTrace();
154 | }
155 | }
156 | } else if (statusString == null){
157 | // a null statusString may indicate a network connection error.
158 | return -2;
159 | }
160 | return -1;
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/fragments/AlertsFragment.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.fragments;
2 |
3 |
4 | import com.sdl.mobileweather.R;
5 |
6 | import android.os.Bundle;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.TextView;
11 |
12 | public class AlertsFragment extends BaseFragment {
13 |
14 | public static final String TEMP_TEXT = "ALERTS";
15 |
16 | @Override
17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
18 | View v = inflater.inflate(R.layout.fragment_alerts, null);
19 | TextView tv = (TextView) v.findViewById(R.id.alerts_msg);
20 | tv.setText(TEMP_TEXT);
21 | return v;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/fragments/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.fragments;
2 |
3 |
4 | import com.sdl.mobileweather.R;
5 |
6 | import android.app.Fragment;
7 | import android.os.Bundle;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 |
13 | public class BaseFragment extends Fragment {
14 |
15 | @Override
16 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
17 | View v = inflater.inflate(R.layout.fragment_base, null);
18 | return v;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/fragments/ConditionsFragment.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.fragments;
2 |
3 |
4 | import java.util.Locale;
5 |
6 | import android.os.Bundle;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 |
13 | import com.sdl.mobileweather.R;
14 | import com.sdl.mobileweather.artifact.WeatherLocation;
15 | import com.sdl.mobileweather.processor.ImageProcessor;
16 | import com.sdl.mobileweather.weather.UnitConverter;
17 | import com.sdl.mobileweather.weather.WeatherConditions;
18 | import com.sdl.mobileweather.weather.WeatherDataManager;
19 |
20 |
21 | public class ConditionsFragment extends BaseFragment {
22 |
23 | private ImageView mConditionsIconView;
24 | private TextView mConditionsTextView;
25 | private TextView mCurrentTempView;
26 | private TextView mAdjustedTempView;
27 | private TextView mWindSpeedView;
28 | private TextView mHumidityView;
29 | private TextView mLocationTextView;
30 | private WeatherDataManager mDataManager;
31 |
32 | @Override
33 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
34 | View v = inflater.inflate(R.layout.fragment_conditions, null);
35 | mConditionsIconView = (ImageView) v.findViewById(R.id.conditionsIcon);
36 | mConditionsTextView = (TextView) v.findViewById(R.id.conditionsText);
37 | mCurrentTempView = (TextView) v.findViewById(R.id.currentTemp);
38 | mAdjustedTempView = (TextView) v.findViewById(R.id.adjustedTemp);
39 | mWindSpeedView = (TextView) v.findViewById(R.id.windSpeed);
40 | mHumidityView = (TextView) v.findViewById(R.id.humidity);
41 |
42 |
43 |
44 |
45 | mLocationTextView = (TextView) v.findViewById(R.id.conditionsLocationTextView);
46 |
47 | mDataManager = WeatherDataManager.getInstance();
48 | if (mDataManager != null) {
49 | WeatherConditions conditions = mDataManager.getWeatherConditions();
50 | String units = mDataManager.getUnits();
51 | WeatherLocation location = mDataManager.getCurrentLocation();
52 | if (conditions != null) {
53 | setConditions(conditions, units);
54 | }
55 | if (location != null) {
56 | setLocation(location);
57 | }
58 | }
59 |
60 | return v;
61 | }
62 |
63 | public void updateLocation() {
64 | if (mDataManager != null) {
65 | WeatherLocation location = mDataManager.getCurrentLocation();
66 | if (location != null) {
67 | setLocation(location);
68 | }
69 | }
70 | }
71 |
72 |
73 |
74 | public void setLocation(WeatherLocation location) {
75 | if (location != null) {
76 | String locationtext = "";
77 | if (mLocationTextView != null){
78 | if (location.city != null){
79 | locationtext = location.city;
80 | }
81 | if (location.state != null){
82 | if (location.city != null){
83 | locationtext += ", " + location.state;
84 | }
85 | else{
86 | locationtext = location.state;
87 | }
88 | }
89 | mLocationTextView.setText(locationtext);
90 | }
91 | }
92 | }
93 |
94 | public void updateConditions() {
95 | if (mDataManager != null) {
96 | WeatherConditions conditions = mDataManager.getWeatherConditions();
97 | String units = mDataManager.getUnits();
98 | if (conditions != null) {
99 | setConditions(conditions, units);
100 | }
101 | }
102 | }
103 |
104 | /**
105 | * Store the current conditions in the fragment
106 | * @param conditions
107 | */
108 | public void setConditions(WeatherConditions conditions, String units) {
109 | if (conditions != null) {
110 | Float temperature = conditions.temperature;
111 | Float windSpeed = conditions.windSpeed;
112 | Float humidity = conditions.humidity;
113 | Float adjustedTemperature = conditions.feelsLikeTemperature;
114 | String temp = null;
115 | String wind = null;
116 | String humid = null;
117 | String adjTemp = null;
118 | String tempUnits = null;
119 | String speedUnits = null;
120 |
121 | if ((getResources().getString(R.string.units_imperial)).equalsIgnoreCase(units) || units == null) {
122 | if (temperature != null)
123 | temperature = Float.valueOf(UnitConverter.convertTemperatureToImperial(temperature.floatValue()));
124 | if (windSpeed != null)
125 | windSpeed = Float.valueOf(UnitConverter.convertSpeedToImperial(windSpeed.floatValue()));
126 | if (adjustedTemperature != null)
127 | adjustedTemperature = Float.valueOf(UnitConverter.convertTemperatureToImperial(adjustedTemperature.floatValue()));
128 |
129 | tempUnits = getResources().getString(R.string.units_imp_temp_short);
130 | speedUnits = getResources().getString(R.string.units_imp_speed_short);
131 | }else {
132 | tempUnits = getResources().getString(R.string.units_metric_temp_short);
133 | speedUnits = getResources().getString(R.string.units_metric_speed_short);
134 | }
135 | if (temperature != null)
136 | temp = String.format(Locale.getDefault(), "%.0f \u00B0 %s", temperature.floatValue(), tempUnits);
137 | if (windSpeed != null)
138 | wind = String.format(Locale.getDefault(), getResources().getString(R.string.conditions_windspeed) + ": %.0f %s", windSpeed.floatValue(), speedUnits);
139 | if (humidity != null)
140 | humid = String.format(Locale.getDefault(), getResources().getString(R.string.conditions_humidity) + ": %.0f %%", humidity.floatValue());
141 | if (adjustedTemperature != null)
142 | adjTemp = String.format(Locale.getDefault(), getResources().getString(R.string.conditions_feelslike) + ": %.0f \u00B0 %s", adjustedTemperature.floatValue(), tempUnits);
143 |
144 | mCurrentTempView.setText(temp);
145 | mConditionsTextView.setText(conditions.conditionTitle);
146 | mAdjustedTempView.setText(adjTemp);
147 | mWindSpeedView.setText(wind);
148 | mHumidityView.setText(humid);
149 |
150 | if (conditions.conditionId != null)
151 | ImageProcessor.setConditionsImage(mConditionsIconView, conditions.conditionId);
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/fragments/ForecastFragment.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.fragments;
2 |
3 |
4 | import com.sdl.mobileweather.R;
5 | import com.sdl.mobileweather.adapter.ForecastListAdapter;
6 | import com.sdl.mobileweather.artifact.WeatherLocation;
7 | import com.sdl.mobileweather.weather.Forecast;
8 | import com.sdl.mobileweather.weather.WeatherDataManager;
9 |
10 | import android.app.Activity;
11 | import android.os.Bundle;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.AdapterView;
16 | import android.widget.ListView;
17 | import android.widget.TextView;
18 |
19 | public class ForecastFragment extends BaseFragment {
20 | private View mFragmentView;
21 | private TextView mLocationTextView;
22 | private ListView mForecastListView;
23 | private WeatherDataManager mDataManager;
24 | private ForecastListAdapter mAdapter;
25 |
26 | @Override
27 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
28 | mFragmentView = inflater.inflate(R.layout.fragment_forecast, null);
29 | mLocationTextView = (TextView) mFragmentView.findViewById(R.id.forecastLocationTextView);
30 | mForecastListView = (ListView) mFragmentView.findViewById(R.id.forecastListView);
31 |
32 | mDataManager = WeatherDataManager.getInstance();
33 | if (mDataManager != null) {
34 | Forecast[] forecast = mDataManager.getForecast();
35 | String units = mDataManager.getUnits();
36 | WeatherLocation location = mDataManager.getCurrentLocation();
37 | if (location != null) {
38 | setLocation(location);
39 | }
40 | if (forecast != null) {
41 | setForecast(forecast, units);
42 | }
43 | else {
44 | Forecast loadingForecast = new Forecast();
45 | loadingForecast.conditionTitle = getResources().getString(R.string.forecast_loading);
46 | Forecast[] loading = { loadingForecast };
47 | setForecast(loading, units);
48 | }
49 | }
50 |
51 | return mFragmentView;
52 | }
53 |
54 | public void updateLocation() {
55 | if (mDataManager != null) {
56 | WeatherLocation location = mDataManager.getCurrentLocation();
57 | if (location != null) {
58 | setLocation(location);
59 | }
60 | }
61 | }
62 |
63 | public void setLocation(WeatherLocation location) {
64 | if (location != null) {
65 | String locationtext = "";
66 | if (mLocationTextView != null){
67 | if (location.city != null){
68 | locationtext = location.city;
69 | }
70 | if (location.state != null){
71 | if (location.city != null){
72 | locationtext += ", " + location.state;
73 | }
74 | else{
75 | locationtext = location.state;
76 | }
77 | }
78 | mLocationTextView.setText(locationtext);
79 | }
80 | }
81 | }
82 |
83 |
84 | public void updateForecast() {
85 | if (mDataManager != null) {
86 | Forecast[] forecast = mDataManager.getForecast();
87 | String units = mDataManager.getUnits();
88 | if (forecast != null) {
89 | setForecast(forecast, units);
90 | }
91 | }
92 | }
93 |
94 | /**
95 | * Store the current forecast in the fragment
96 | * @param forecast
97 | */
98 | public void setForecast(Forecast[] forecast, String units) {
99 | if (forecast != null) {
100 | Activity context = getActivity();
101 | mAdapter = new ForecastListAdapter(context, forecast, context);
102 | mForecastListView.setAdapter(mAdapter);
103 | mForecastListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
104 | @Override
105 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
106 | mAdapter.toggleForecastType(position);
107 | mAdapter.notifyDataSetChanged();
108 | }
109 | });
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/localization/LocalizationUtil.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.localization;
2 |
3 | import java.util.Locale;
4 |
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.res.Configuration;
8 |
9 | import com.sdl.mobileweather.R;
10 | import com.sdl.mobileweather.openweathermap.OpenWeatherMapService;
11 | import com.smartdevicelink.proxy.rpc.enums.Language;
12 | //import com.sdl.mobileweather.forecastio.ForecastIoService;
13 | import com.sdl.mobileweather.smartdevicelink.SdlApplication;
14 | import com.sdl.mobileweather.weather.WeatherDataManager;
15 | import com.sdl.mobileweather.weather.WeatherUpdateWakefulReceiver;
16 |
17 | public class LocalizationUtil {
18 | private static LocalizationUtil instance;
19 | // variables to save the original and adjusted Locales
20 | private String mSavedLocaleCountry = "US";
21 | private String mSavedLocaleLanguage = "en";
22 | private String mAdjustedLocaleCountry = "US";
23 | private String mAdjustedLocaleLanguage = "en";
24 |
25 | private final Object mSavedLocaleCountryLock = new Object();
26 | private final Object mSavedLocaleLanguageLock = new Object();
27 | private final Object mAdjustedLocaleCountryLock = new Object();
28 | private final Object mAdjustedLocaleLanguageLock = new Object();
29 |
30 | static{
31 | instance = null;
32 | }
33 |
34 | private static synchronized void setInstance(LocalizationUtil loc){
35 | instance = loc;
36 | }
37 |
38 | public static synchronized LocalizationUtil getInstance(){
39 | return instance;
40 | }
41 |
42 | public LocalizationUtil(){
43 | LocalizationUtil.setInstance(this);
44 | }
45 |
46 |
47 | public String getLocaleCountry(){
48 | synchronized (mSavedLocaleCountryLock){
49 | return mSavedLocaleCountry;
50 | }
51 | }
52 |
53 | public void setLocaleCountry(String country){
54 | synchronized (mSavedLocaleCountryLock) {
55 | this.mSavedLocaleCountry = country;
56 | }
57 | }
58 |
59 | public String getLocaleLanguage(){
60 | synchronized (mSavedLocaleLanguageLock){
61 | return mSavedLocaleLanguage;
62 | }
63 | }
64 |
65 | public void setLocaleLanguage(String language){
66 | synchronized (mSavedLocaleLanguageLock){
67 | this.mSavedLocaleLanguage = language;
68 | }
69 | }
70 |
71 | public String getAdjustedLocaleCountry(){
72 | synchronized (mAdjustedLocaleCountryLock){
73 | return mAdjustedLocaleCountry;
74 | }
75 | }
76 |
77 | public void setAdjustedLocaleCountry(String country){
78 | synchronized (mAdjustedLocaleCountryLock){
79 | this.mAdjustedLocaleCountry = country;
80 | }
81 | }
82 |
83 | public String getAdjustedLocaleLanguage(){
84 | synchronized (mAdjustedLocaleLanguageLock){
85 | return mAdjustedLocaleLanguage;
86 | }
87 | }
88 |
89 | public void setAdjustedLocaleLanguage(String language){
90 | synchronized (mAdjustedLocaleLanguageLock){
91 | this.mAdjustedLocaleLanguage = language;
92 | }
93 | }
94 |
95 |
96 |
97 | public void determineLocale(Language sync_language) {
98 | // derive locales for device, get language (VR+TTS) that is used currently by SYNC voice engine(VR+TTS)
99 | mSavedLocaleCountry = (Locale.getDefault()).getCountry();
100 | mSavedLocaleLanguage = (Locale.getDefault()).getLanguage();
101 |
102 | switch(sync_language){
103 | /*
104 | * Map codes for the representation of languages according to ISO 639-1 Code
105 | * Map codes for the representation of countries according to ISO 3166-2 Code
106 | */
107 |
108 | case EN_GB:
109 | mAdjustedLocaleLanguage = "en";
110 | mAdjustedLocaleCountry = "GB";
111 | break;
112 | case EN_US:
113 | mAdjustedLocaleLanguage ="en";
114 | mAdjustedLocaleCountry = "US";
115 | break;
116 | case DE_DE:
117 | mAdjustedLocaleLanguage = "de";
118 | mAdjustedLocaleCountry = "DE";
119 | break;
120 | case PT_BR:
121 | mAdjustedLocaleLanguage = "pt";
122 | mAdjustedLocaleCountry = "BR";
123 | break;
124 | case PT_PT:
125 | mAdjustedLocaleLanguage = "pt";
126 | mAdjustedLocaleCountry = "PT";
127 | break;
128 | case ES_ES:
129 | mAdjustedLocaleLanguage = "es";
130 | mAdjustedLocaleCountry = "ES";
131 | break;
132 | case ES_MX:
133 | mAdjustedLocaleLanguage = "es";
134 | mAdjustedLocaleCountry = "MX";
135 | break;
136 | /* fall through for the countries localization is not yet available */
137 | case AR_SA:/*
138 | mAdjustedLocaleLanguage = "ar";
139 | mAdjustedLocaleCountry = "SA";
140 | break;*/
141 | case CS_CZ:/*
142 | mAdjustedLocaleLanguage = "cs";
143 | mAdjustedLocaleCountry = "CZ";
144 | break;*/
145 | case DA_DK:/*
146 | mAdjustedLocaleLanguage = "da";
147 | mAdjustedLocaleCountry = "DK";
148 | break;*/
149 | case EN_AU:/*
150 | mAdjustedLocaleLanguage = "en";
151 | mAdjustedLocaleCountry = "AU";
152 | break;*/
153 | case FR_CA:/*
154 | mAdjustedLocaleLanguage = "fr";
155 | mAdjustedLocaleCountry = "CA";
156 | break;*/
157 | case FR_FR:/*
158 | mAdjustedLocaleLanguage = "fr";
159 | mAdjustedLocaleCountry = "FR";
160 | break;*/
161 | case IT_IT:/*
162 | mAdjustedLocaleLanguage = "it";
163 | mAdjustedLocaleCountry = "IT";
164 | break;*/
165 | case JA_JP:/*
166 | mAdjustedLocaleLanguage = "ja";
167 | mAdjustedLocaleCountry = "JP" ;
168 | break;*/
169 | case KO_KR:/*
170 | mAdjustedLocaleLanguage = "ko";
171 | mAdjustedLocaleCountry = "KR";
172 | break;*/
173 | case NL_NL:/*
174 | mAdjustedLocaleLanguage = "nl";
175 | mAdjustedLocaleCountry = "NL";
176 | break;*/
177 | case NO_NO:/*
178 | mAdjustedLocaleLanguage = "no";
179 | mAdjustedLocaleCountry = "NO";
180 | break;*/
181 | case PL_PL:/*
182 | mAdjustedLocaleLanguage = "pl";
183 | mAdjustedLocaleCountry = "PL";
184 | break;*/
185 | case RU_RU:/*
186 | mAdjustedLocaleLanguage = "ru";
187 | mAdjustedLocaleCountry = "RU";
188 | break;*/
189 | case SV_SE:/*
190 | mAdjustedLocaleLanguage = "sv";
191 | mAdjustedLocaleCountry = "SE";
192 | break;*/
193 | case TR_TR:/*
194 | mAdjustedLocaleLanguage = "tr";
195 | mAdjustedLocaleCountry = "TR";
196 | break;*/
197 | case ZH_CN:/*
198 | mAdjustedLocaleLanguage = "zh";
199 | mAdjustedLocaleCountry = "CN";
200 | break;*/
201 | case ZH_TW:/*
202 | mAdjustedLocaleLanguage = "zh";
203 | mAdjustedLocaleCountry = "TW";
204 | break;*/
205 | default:
206 | mAdjustedLocaleLanguage = "en";
207 | mAdjustedLocaleCountry = "US";
208 | break;
209 | }
210 | return;
211 | }
212 |
213 | public void changeLocale(String language, String country, Context context){
214 | // change locale to enforce usage of localization resource
215 | WeatherDataManager mDataManager;
216 | Configuration config = context.getResources().getConfiguration();
217 | Locale locale = new Locale(language, country);
218 | Locale.setDefault(locale);
219 | Configuration conf = new Configuration(config);
220 | conf.locale = locale;
221 | context.getResources().updateConfiguration(conf, context.getResources().getDisplayMetrics());
222 | mDataManager = WeatherDataManager.getInstance();
223 | if(mDataManager != null){
224 | mDataManager.setUnits(context.getResources().getString(R.string.units_default));
225 | }
226 | Context mAppContext = SdlApplication.getInstance().getApplicationContext();
227 | Intent mUpdateIntent = new Intent(mAppContext, WeatherUpdateWakefulReceiver.class);
228 | //mUpdateIntent.putExtra("weather_update_service", ForecastIoService.class.getName());
229 | mUpdateIntent.putExtra("weather_update_service", OpenWeatherMapService.class.getName());
230 | mAppContext.sendBroadcast(mUpdateIntent);
231 | return;
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/location/LocationJsonProcessor.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.location;
2 |
3 | import org.json.JSONObject;
4 |
5 | import com.sdl.mobileweather.artifact.WeatherLocation;
6 |
7 | public interface LocationJsonProcessor {
8 |
9 | public WeatherLocation getLocation(JSONObject location);
10 | }
11 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/location/PlayServicesConnectionChecker.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.location;
2 |
3 | import android.util.Log;
4 |
5 | import com.sdl.mobileweather.smartdevicelink.SdlApplication;
6 | import com.google.android.gms.common.ConnectionResult;
7 | import com.google.android.gms.common.GooglePlayServicesUtil;
8 |
9 | public class PlayServicesConnectionChecker {
10 |
11 | public static boolean servicesConnected() {
12 | // Check that Google Play services is available
13 | int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(SdlApplication.getInstance());
14 | // If Google Play services is available
15 | if (ConnectionResult.SUCCESS == resultCode) {
16 | Log.d(SdlApplication.TAG, "Google Play services is available.");
17 | return true;
18 | // Google Play services was not available for some reason
19 | } else {
20 | Log.e(SdlApplication.TAG, "Google Play services are not available!");
21 | }
22 | return false;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/openweathermap/OpenWeatherMapLocationJsonProcessor.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.openweathermap;
2 |
3 | import com.sdl.mobileweather.artifact.GPSLocation;
4 | import com.sdl.mobileweather.artifact.WeatherLocation;
5 | import com.sdl.mobileweather.location.LocationJsonProcessor;
6 |
7 | import org.json.JSONException;
8 | import org.json.JSONObject;
9 |
10 | //TODO - Convert WUnderground specific code to OpenWeatherMap specific code
11 | public class OpenWeatherMapLocationJsonProcessor implements LocationJsonProcessor {
12 | private static final String LOCATION = "location";
13 | private static final String STATE = "state";
14 | private static final String CITY = "city";
15 | private static final String LATITUDE = "lat";
16 | private static final String LONGITUDE = "lon";
17 | private static final String ZIPCODE = "zip";
18 |
19 | @Override
20 | public WeatherLocation getLocation(JSONObject jsonRoot) {
21 | WeatherLocation location = null;
22 |
23 | if (jsonRoot != null) {
24 | location = new WeatherLocation();
25 | try {
26 | JSONObject jsonLocation = jsonRoot.getJSONObject(LOCATION);
27 | location.state = jsonLocation.getString(STATE);
28 | location.city = jsonLocation.getString(CITY);
29 | location.zipCode = jsonLocation.getString(ZIPCODE);
30 | location.gpsLocation = new GPSLocation();
31 | location.gpsLocation.latitude = jsonLocation.getString(LATITUDE);
32 | location.gpsLocation.longitude = jsonLocation.getString(LONGITUDE);
33 | } catch (JSONException e) {
34 | // TODO Auto-generated catch block
35 | e.printStackTrace();
36 | }
37 | }
38 | return location;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/openweathermap/OpenWeatherMapService.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.openweathermap;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.util.Log;
6 |
7 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
8 |
9 | import com.sdl.mobileweather.artifact.GPSLocation;
10 | import com.sdl.mobileweather.artifact.WeatherLocation;
11 | import com.sdl.mobileweather.connection.HttpConnection;
12 | import com.sdl.mobileweather.processor.JsonProcessor;
13 | import com.sdl.mobileweather.smartdevicelink.SdlApplication;
14 | import com.sdl.mobileweather.weather.Forecast;
15 | import com.sdl.mobileweather.weather.WeatherAlert;
16 | import com.sdl.mobileweather.weather.WeatherConditions;
17 | import com.sdl.mobileweather.weather.WeatherService;
18 |
19 | import org.json.JSONObject;
20 |
21 | import java.net.MalformedURLException;
22 | import java.net.URL;
23 |
24 | public class OpenWeatherMapService extends WeatherService {
25 |
26 | /**
27 | * API key used for OpenWeatherMap API
28 | */
29 | private static final String API_KEY = "INSERT YOUR OWN API KEY";
30 | private static final String URI_SCHEME = "https";
31 | /**
32 | * Base request URL for OpenWeatherMap
33 | */
34 | private static final String BASE_URL = "api.openweathermap.org";
35 | private static final String DATA_PATH = "data";
36 | /**
37 | * A number value in the suggested API call to OpenWeatherMap
38 | *
39 | * I believe this value in the API call represents the version number of the API.
40 | * It may need to change if OpenWeatherMap updates their API
41 | *
42 | * - Noah Stanford (noah@livio.io)
43 | */
44 | private static final String VERSION = "2.5";
45 | /**
46 | * This API call type provides current weather, minute forecast for 1 hour, hourly forecast for 48 hours,
47 | * daily forecast for 7 days, global weather alerts and historical data for 5 previous day for any location
48 | */
49 | private static final String ONE_CALL_API_CALL_TYPE = "onecall";
50 | private static final String LATITUDE_PARAMETER = "lat";
51 | private static final String LONGITUDE_PARAMETER = "lon";
52 | private static final String UNITS_PARAMETER = "units";
53 | private static final String METRIC = "metric";
54 | /**
55 | * This parameter is used to specify the API key for the API call
56 | */
57 | private static final String APP_ID_PARAMETER = "appid";
58 | /**
59 | * This is 0 because it's the first index and only one URL is used for weather data at a time
60 | */
61 | private static final int ONLY_URL_INDEX = 0;
62 | public static final int REQUEST_SUCCESS = -1;
63 | public static final int REQUEST_FAILURE = -2;
64 | public static final String TAG = "MobileWeather";
65 |
66 |
67 | public OpenWeatherMapService() {
68 | super();
69 | mWeatherProcessor = new OpenWeatherMapWeatherJsonProcessor();
70 | }
71 |
72 | @Override
73 | protected void updateWeatherData(URL... urls) {
74 | HttpConnection httpRequest = new HttpConnection();
75 | JsonProcessor jsonProcessor = new JsonProcessor();
76 | WeatherConditions conditions = null;
77 | Forecast[] forecast = null;
78 | Forecast[] hourlyForecast = null;
79 | WeatherAlert[] alerts = null;
80 | String httpResult = null;
81 |
82 | Log.d(TAG, "updateWeatherData");
83 | if (urls.length == 1 && mDataManager != null && mWeatherProcessor != null) {
84 | LocalBroadcastManager lbManager = LocalBroadcastManager.getInstance(this);
85 | Log.d(TAG, "updateWeatherData - valid urls");
86 | if (urls[ONLY_URL_INDEX] != null) {
87 | Log.d(TAG, urls[ONLY_URL_INDEX].toString());
88 | Log.d(TAG, "updateWeatherData - getting json");
89 | httpResult = httpRequest.sendRequest(urls[ONLY_URL_INDEX], HttpConnection.RequestMethod.GET, null, "application/json");
90 | int statusCode = httpRequest.getStatusCode(httpResult);
91 | if (statusCode == REQUEST_SUCCESS) {
92 | Log.d(TAG, "updateWeatherData - parsing conditions json");
93 | JSONObject jsonRoot = jsonProcessor.getJsonFromString(httpResult);
94 | if (jsonRoot != null) {
95 | Log.d(TAG, "updateWeatherData - parsing conditions");
96 | conditions = mWeatherProcessor.getWeatherConditions(jsonRoot);
97 | mDataManager.setWeatherConditions(conditions);
98 | if (conditions != null) {
99 | Log.d(TAG, "updateWeatherData - new conditions");
100 | Intent intent = new Intent("com.sdl.mobileweather.WeatherConditions");
101 | lbManager.sendBroadcast(intent);
102 | }
103 |
104 | Log.d(TAG, "updateWeatherData - parsing forecast");
105 | forecast = mWeatherProcessor.getForecast(jsonRoot);
106 | mDataManager.setForecast(forecast);
107 | if (forecast != null) {
108 | Log.d(TAG, "updateWeatherData - new forecast");
109 | Intent intent = new Intent("com.sdl.mobileweather.Forecast");
110 | lbManager.sendBroadcast(intent);
111 | }
112 |
113 | Log.d(TAG, "updateWeatherData - parsing hourly forecast");
114 | hourlyForecast = mWeatherProcessor.getHourlyForecast(jsonRoot);
115 | mDataManager.setHourlyForecast(hourlyForecast);
116 | if (hourlyForecast != null) {
117 | Intent intent = new Intent("com.sdl.mobileweather.HourlyForecast");
118 | lbManager.sendBroadcast(intent);
119 | }
120 |
121 | alerts = mWeatherProcessor.getAlerts(jsonRoot);
122 | mDataManager.setAlerts(alerts);
123 | if (alerts != null) {
124 | Log.d(TAG, "updateWeatherData - new Alerts");
125 | Intent intent = new Intent("com.sdl.mobileweather.Alerts");
126 | lbManager.sendBroadcast(intent);
127 | }
128 | }
129 |
130 | reportApiAvail(true);
131 |
132 | } else if (statusCode == REQUEST_FAILURE){
133 | reportConnectionAvail(false);
134 | } else {
135 | reportApiAvail(false);
136 | }
137 | }
138 |
139 |
140 | WeatherLocation loc = mDataManager.getCurrentLocation();
141 | if (loc != null) {
142 | mDataManager.setLastCity(loc.city);
143 | mDataManager.setLastState(loc.state);
144 | }
145 | }
146 | }
147 |
148 | /**
149 | * Creates service specific weather data URLs.
150 | */
151 | @Override
152 | protected URL[] getURLs(WeatherLocation currentLocation) {
153 | URL oneCallURL = null;
154 | try {
155 | oneCallURL = buildOneCallURL(currentLocation);
156 | Log.d(SdlApplication.TAG, currentLocation.gpsLocation.latitude + "," + currentLocation.gpsLocation.longitude);
157 | } catch (MalformedURLException e) {
158 | e.printStackTrace();
159 | }
160 | return new URL[] { oneCallURL };
161 | }
162 |
163 | private URL buildOneCallURL(WeatherLocation currentLocation) throws MalformedURLException {
164 | Uri.Builder builder = new Uri.Builder();
165 | builder.scheme(URI_SCHEME)
166 | .authority(BASE_URL)
167 | .appendPath(DATA_PATH)
168 | .appendPath(VERSION)
169 | .appendPath(ONE_CALL_API_CALL_TYPE)
170 | .appendQueryParameter(LATITUDE_PARAMETER, currentLocation.gpsLocation.latitude)
171 | .appendQueryParameter(LONGITUDE_PARAMETER, currentLocation.gpsLocation.longitude)
172 | .appendQueryParameter(UNITS_PARAMETER, METRIC)
173 | .appendQueryParameter(APP_ID_PARAMETER, API_KEY);
174 |
175 | Uri everythingUri = builder.build();
176 | return new URL(everythingUri.toString());
177 | }
178 |
179 | public int getRequestStatus() {
180 | String httpResult = null;
181 | HttpConnection httpRequest = new HttpConnection();
182 | WeatherLocation location = new WeatherLocation();
183 | location.gpsLocation = new GPSLocation();
184 | location.gpsLocation.latitude = "0.0";
185 | location.gpsLocation.longitude = "0.0";
186 |
187 | URL[] urls = getURLs(location);
188 | httpResult = httpRequest.sendRequest(urls[ONLY_URL_INDEX], HttpConnection.RequestMethod.GET, null, "application/json");
189 | return httpRequest.getStatusCode(httpResult);
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/processor/ImageProcessor.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.processor;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.net.Uri;
8 | import android.widget.ImageView;
9 |
10 | import com.sdl.mobileweather.BuildConfig;
11 | import com.sdl.mobileweather.smartdevicelink.SdlApplication;
12 |
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.net.URL;
16 | import java.nio.ByteBuffer;
17 | import java.util.Collections;
18 | import java.util.HashMap;
19 | import java.util.Map;
20 | import java.util.concurrent.ExecutorService;
21 | import java.util.concurrent.Executors;
22 |
23 | import javax.net.ssl.HttpsURLConnection;
24 |
25 | public class ImageProcessor {
26 | private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
27 | private static final String IMAGE_DIR = "imageDir";
28 | private static final String PNG_EXTENSION = ".png";
29 | private static final int BITMAP_QUALITY = 100;
30 | private static final String TAG = "ImageProcessor";
31 | private static final String RESOURCE_SCHEME = "android.resource://";
32 | private static final String DRAWABLE_FOLDER = "drawable";
33 | private static final String ICON_RESOURCE_TEMPLATE = "ic_%s";
34 |
35 | private static final Map mConditionsImageMap =
36 | Collections.unmodifiableMap(new HashMap() {
37 | private static final long serialVersionUID = 1L;
38 | {
39 | put("sunny.gif", "clearday");
40 | put("clear.gif", "clearday");
41 | put("mostlysunny.gif", "partlycloudyday");
42 | put("partlysunny.gif", "partlysunny");
43 | put("hazy.gif", "hazy");
44 | put("fog.gif", "fogcloudy");
45 | put("partlycloudy.gif", "partlycloudyday");
46 | put("chancetstorms.gif", "chancethunderstorm");
47 | put("tstorms.gif", "thunderstorm");
48 | put("chancerain.gif", "lightrain");
49 | put("rain.gif", "rain");
50 | put("chanceflurries.gif", "chancesnow");
51 | put("flurries.gif", "lightsnow");
52 | put("chancesnow.gif", "chancesnow");
53 | put("snow.gif", "snow");
54 | put("chancesleet.gif", "sleet");
55 | put("sleet.gif", "sleet");
56 | put("mostlycloudy.gif", "partlysunny");
57 | put("cloudy.gif", "cloudy");
58 |
59 | put("nt_sunny.gif", "clearday");
60 | put("nt_clear.gif", "clearday");
61 | put("nt_mostlysunny.gif", "partlycloudyday");
62 | put("nt_partlysunny.gif", "partlysunny");
63 | put("nt_hazy.gif", "hazy");
64 | put("nt_fog.gif", "fogcloudy");
65 | put("nt_partlycloudy.gif", "partlycloudyday");
66 | put("nt_chancetstorms.gif", "chancethunderstorm");
67 | put("nt_tstorms.gif", "thunderstorm");
68 | put("nt_chancerain.gif", "lightrain");
69 | put("nt_rain.gif", "rain");
70 | put("nt_chanceflurries.gif", "chancesnow");
71 | put("nt_flurries.gif", "lightsnow");
72 | put("nt_chancesnow.gif", "chancesnow");
73 | put("nt_snow.gif", "snow");
74 | put("nt_chancesleet.gif", "sleet");
75 | put("nt_sleet.gif", "sleet");
76 | put("nt_mostlycloudy.gif", "partlysunny");
77 | put("nt_cloudy.gif", "cloudy");
78 |
79 | put("clear-day.gif", "clearday");
80 | put("clear-night.gif", "clearnight");
81 | //put("rain.gif", "rain");
82 | //put("snow.gif", "snow");
83 | //put("sleet.gif", "sleet");
84 | put("wind.gif", "windycloudy");
85 | //put("fog.gif", "fog");
86 | //put("cloudy.gif", "cloudy");
87 | put("partly-cloudy-day.gif", "partlycloudyday");
88 | put("partly-cloudy-night.gif", "partlycloudynight");
89 | }});
90 |
91 | public static String getMappedConditionsImageName(String conditionsImage, boolean small) {
92 | String suffix = "";
93 | if (small) {
94 | suffix = "_50";
95 | }
96 | if (mConditionsImageMap.containsKey(conditionsImage)) {
97 | return mConditionsImageMap.get(conditionsImage);
98 | }
99 | else {
100 | return null;
101 | }
102 | }
103 |
104 | public static Bitmap getBitmapFromResources(String conditionId) {
105 | String imageName = String.format(ICON_RESOURCE_TEMPLATE, conditionId);
106 | Resources resources = SdlApplication.getInstance().getResources();
107 | int resId = resources.getIdentifier(imageName, "drawable", "com.sdl.mobileweather");
108 | return BitmapFactory.decodeResource(resources, resId);
109 | }
110 |
111 | public static byte[] getBytesFromURL(URL url) {
112 | byte[] bytes = null;
113 | HttpsURLConnection connection = null;
114 | try {
115 | connection = (HttpsURLConnection) url.openConnection();
116 | connection.setDoInput(true);
117 | connection.connect();
118 | InputStream inputStream = connection.getInputStream();
119 | final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
120 | int size = bitmap.getHeight() * bitmap.getRowBytes();
121 | ByteBuffer buffer = ByteBuffer.allocate(size);
122 | bitmap.copyPixelsToBuffer(buffer);
123 | bytes = buffer.array();
124 |
125 | } catch (IOException e) {
126 | e.printStackTrace();
127 | }
128 | return bytes;
129 | }
130 |
131 | public static Uri getImageUriFromURL(String imageName, URL url, Context context) {
132 | return Uri.parse(url.toString());
133 | }
134 |
135 | public static String getFileFromURL(URL url) {
136 | if (url != null) {
137 | return url.getFile();
138 | }
139 | else {
140 | return null;
141 | }
142 | }
143 |
144 | public static void setConditionsImage(ImageView imageView, String conditionId) {
145 |
146 | Bitmap bitmap = getBitmapFromResources(conditionId);
147 |
148 | imageView.setImageBitmap(bitmap);
149 | }
150 |
151 | public static Uri getWeatherIconUri(String iconId) {
152 |
153 | String iconFileString = String.format(ICON_RESOURCE_TEMPLATE, iconId);
154 | return Uri.parse(RESOURCE_SCHEME + BuildConfig.APPLICATION_ID + "/" + DRAWABLE_FOLDER + "/" + iconFileString);
155 | }
156 | }
157 |
158 |
159 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/processor/JsonProcessor.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.processor;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | public class JsonProcessor {
7 |
8 | /**
9 | * Process a String containing JSON into a JSONObject.
10 | * @param data the JSON String
11 | * @return the root JSON Object.
12 | */
13 | public JSONObject getJsonFromString(String data) {
14 | JSONObject jsonObject = null;
15 |
16 | try {
17 | jsonObject = new JSONObject(data);
18 | } catch (JSONException e) {
19 | // TODO Auto-generated catch block
20 | e.printStackTrace();
21 | }
22 |
23 | return jsonObject;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/smartdevicelink/SdlActivity.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.smartdevicelink;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.view.Menu;
7 | import android.view.MenuItem;
8 |
9 | import com.sdl.mobileweather.weather.AbbreviationDictionary;
10 |
11 | public class SdlActivity extends Activity {
12 | private boolean activityOnTop;
13 |
14 | /**
15 | * Activity is moving to the foreground.
16 | * Set this activity as the current activity and that it is on top.
17 | * Update the lockscreen.
18 | */
19 | @Override
20 | protected void onResume() {
21 | super.onResume();
22 | SdlApplication.setCurrentActivity(this);
23 | activityOnTop = true;
24 | }
25 |
26 | /**
27 | * Activity becoming partially visible (obstructed by another).
28 | * Activity if no longer on top.
29 | */
30 | @Override
31 | protected void onPause() {
32 | activityOnTop = false;
33 | // Notify App that activity is leaving forground
34 | if (SdlApplication.getCurrentActivity() == this) {
35 | SdlApplication.setCurrentActivity(null);
36 | }else{
37 | if(SdlApplication.getCurrentActivity() == null){
38 | Log.v(SdlApplication.TAG, "Current activity already null.");
39 | }else{
40 | Log.v(SdlApplication.TAG, "This activity is not on top.");
41 | }
42 | }
43 | super.onPause();
44 | }
45 |
46 | @Override
47 | protected void onCreate(Bundle savedInstanceState) {
48 | super.onCreate(savedInstanceState);
49 | if(!AbbreviationDictionary.isPrepared())
50 | AbbreviationDictionary.loadDictionary(this);
51 | }
52 |
53 | /**
54 | * Activity is no longer visible on the screen.
55 | */
56 | @Override
57 | protected void onStop() {
58 | // Stop services if no other weather activity has taken foreground
59 | SdlApplication app = SdlApplication.getInstance();
60 | if (app != null) {
61 | app.stopServices();
62 | }else{
63 | Log.d(SdlApplication.TAG, "onStop app==null");
64 | }
65 | super.onStop();
66 | }
67 |
68 | @Override
69 | protected void onDestroy() {
70 | super.onDestroy();
71 | }
72 |
73 | @Override
74 | public boolean onCreateOptionsMenu(Menu menu) {
75 | return true;
76 | }
77 |
78 | @Override
79 | public boolean onOptionsItemSelected(MenuItem item) {
80 | return true;
81 | }
82 |
83 | public boolean isActivityonTop(){
84 | return activityOnTop;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/smartdevicelink/SdlApplication.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.smartdevicelink;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.Application;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.pm.PackageManager.NameNotFoundException;
9 | import android.content.res.Configuration;
10 | import android.util.Log;
11 |
12 | import com.sdl.mobileweather.R;
13 | //import com.sdl.mobileweather.forecastio.ForecastIoService;
14 | import com.sdl.mobileweather.localization.LocalizationUtil;
15 | import com.sdl.mobileweather.location.PlayServicesConnectionChecker;
16 | import com.sdl.mobileweather.location.WeatherLocationServices;
17 | import com.sdl.mobileweather.openweathermap.OpenWeatherMapService;
18 | import com.sdl.mobileweather.weather.WeatherAlarmManager;
19 | import com.sdl.mobileweather.weather.WeatherDataManager;
20 | import com.sdl.mobileweather.weather.WeatherUpdateWakefulReceiver;
21 | import com.sdl.mobileweather.BuildConfig;
22 | import com.smartdevicelink.managers.SdlManager;
23 |
24 | import java.util.Locale;
25 |
26 |
27 | public class SdlApplication extends Application {
28 |
29 | public static final String TAG = "MobileWeather";
30 | private static SdlApplication instance;
31 | private static Activity currentUIActivity;
32 | private WeatherLocationServices mLocationServices;
33 | private WeatherDataManager mDataManager;
34 | private WeatherAlarmManager mWeatherAlarm;
35 | private LocalizationUtil mLocalizationUtil;
36 |
37 |
38 | static {
39 | instance = null;
40 | }
41 |
42 | private static synchronized void setInstance(SdlApplication app) {
43 | instance = app;
44 | }
45 |
46 | public static synchronized SdlApplication getInstance() {
47 | return instance;
48 | }
49 |
50 | public static synchronized void setCurrentActivity(Activity act) {
51 | currentUIActivity = act;
52 | }
53 |
54 | public static synchronized Activity getCurrentActivity() {
55 | return currentUIActivity;
56 | }
57 |
58 | @Override
59 | public void onCreate() {
60 | super.onCreate();
61 | SdlApplication.setInstance(this);
62 | mDataManager = new WeatherDataManager();
63 | // TODO: Fix magic number assignment of update interval
64 | mDataManager.setUpdateInterval(5);
65 | mDataManager.setUnits(getResources().getString(R.string.units_default));
66 | mLocalizationUtil = new LocalizationUtil();
67 | //mWeatherAlarm = new WeatherAlarmManager(ForecastIoService.class);
68 | mWeatherAlarm = new WeatherAlarmManager(OpenWeatherMapService.class);
69 | mLocationServices = null;
70 | if (PlayServicesConnectionChecker.servicesConnected()) {
71 | mLocationServices = new WeatherLocationServices();
72 | }
73 | }
74 |
75 | public void onConfigurationChanged(Configuration newConfig) {
76 | super.onConfigurationChanged(newConfig);
77 | Log.d(TAG, "onConfigurationChanged received");
78 | Context mAppContext = SdlApplication.getInstance().getApplicationContext();
79 | Intent mUpdateIntent = new Intent(mAppContext, WeatherUpdateWakefulReceiver.class);
80 | //mUpdateIntent.putExtra("weather_update_service", ForecastIoService.class.getName());
81 | mUpdateIntent.putExtra("weather_update_service", OpenWeatherMapService.class.getName());
82 | mAppContext.sendBroadcast(mUpdateIntent);
83 | if (mDataManager != null) {
84 | mDataManager.setUnits(getResources().getString(R.string.units_default));
85 | }
86 | mLocalizationUtil.setLocaleCountry((Locale.getDefault()).getCountry());
87 | mLocalizationUtil.setLocaleLanguage((Locale.getDefault()).getLanguage());
88 | }
89 |
90 |
91 | @Override
92 | public void onLowMemory() {
93 | super.onLowMemory();
94 | }
95 |
96 | public void startSdlProxyService() {
97 | Log.i(SdlApplication.TAG, "Starting SmartDeviceLink service");
98 | if (BuildConfig.TRANSPORT.equals("MULTI")) {
99 | Log.i(TAG, "startSdlProxyService: Multiplex Selected");
100 | SdlReceiver.queryForConnectedService(this);
101 | } else if (BuildConfig.TRANSPORT.equals("TCP")) {
102 | Log.i(TAG, "startSdlProxyService: TCP Selected");
103 | Intent proxyIntent = new Intent(this, SdlService.class);
104 | startService(proxyIntent);
105 | }
106 | }
107 |
108 | // Recycle the proxy
109 | public void endSdlProxyInstance() {
110 | SdlService serviceInstance = SdlService.getInstance();
111 | if (serviceInstance != null){
112 | SdlManager sdlManagerInstance = serviceInstance.getSdlManager();
113 | // if proxy exists, reset it
114 | if(sdlManagerInstance != null){
115 | serviceInstance.reset();
116 | // if proxy == null create proxy
117 | } else {
118 | serviceInstance.startProxy();
119 | }
120 | }
121 | }
122 |
123 | public void startWeatherUpdates() {
124 | Log.i(SdlApplication.TAG, "Starting weather updates");
125 | mWeatherAlarm.startPendingLocation();
126 | }
127 |
128 | public void endWeatherUpdates() {
129 | Log.i(SdlApplication.TAG, "Stopping weather updates");
130 | mWeatherAlarm.stop();
131 | }
132 |
133 | public void startLocationServices() {
134 | Log.i(SdlApplication.TAG, "Starting location service");
135 | if (mLocationServices != null) {
136 | mLocationServices.start();
137 | }
138 | }
139 |
140 | public void endLocationServices() {
141 | Log.i(SdlApplication.TAG, "Stopping location service");
142 | if (mLocationServices != null) {
143 | mLocationServices.stop();
144 | }
145 | }
146 |
147 | public void startServices() {
148 | startSdlProxyService();
149 | startLocationServices();
150 | startWeatherUpdates();
151 | }
152 |
153 | public void stopServices() {
154 | boolean noUIActivity;
155 | boolean noApplinkService;
156 |
157 | noUIActivity = (currentUIActivity == null);
158 | noApplinkService = (SdlService.getInstance() == null);
159 |
160 | Log.d(TAG, "Attempting to stop services");
161 | if(noUIActivity && noApplinkService){
162 | Log.d(TAG, "Stopping services");
163 | endWeatherUpdates();
164 | endLocationServices();
165 | return;
166 | }
167 | Log.d(TAG, "Not stopping services");
168 | }
169 |
170 | public void stopServices(boolean appLinkStopping) {
171 | if(appLinkStopping){
172 | if(currentUIActivity == null){
173 | Log.d(TAG, "Attempt force stop services");
174 | endWeatherUpdates();
175 | endLocationServices();
176 | } else {
177 | Log.d(TAG, "Application in foreground on phone. Not stopping loc + weath services");
178 | }
179 | } else {
180 | stopServices();
181 | }
182 | }
183 |
184 | public void showAppVersion(Context context) {
185 |
186 | String appMessage = getResources().getString(R.string.mobileweather_ver_not_available);
187 | String proxyMessage = getResources().getString(R.string.proxy_ver_not_available);
188 | SdlService serviceInstance = SdlService.getInstance();
189 | try {
190 | appMessage = getResources().getString(R.string.mobileweather_ver) +
191 | getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
192 | } catch (NameNotFoundException e) {
193 | Log.d(SdlApplication.TAG, "Can't get package info", e);
194 | }
195 |
196 | proxyMessage = getResources().getString(R.string.proxy_ver) + BuildConfig.VERSION_NAME;
197 | new AlertDialog.Builder(context).setTitle((getResources().getString(R.string.app_ver)))
198 | .setMessage(appMessage + "\r\n" + proxyMessage)
199 | .setNeutralButton(android.R.string.ok, null).create().show();
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/smartdevicelink/SdlReceiver.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.smartdevicelink;
2 |
3 | import android.app.PendingIntent;
4 | import android.bluetooth.BluetoothDevice;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.os.Build;
8 | import android.util.Log;
9 |
10 | import com.smartdevicelink.transport.SdlBroadcastReceiver;
11 | import com.smartdevicelink.transport.SdlRouterService;
12 | import com.smartdevicelink.transport.TransportConstants;
13 | import com.smartdevicelink.util.AndroidTools;
14 |
15 | public class SdlReceiver extends SdlBroadcastReceiver {
16 |
17 |
18 | @Override
19 | public void onReceive(Context context, Intent intent) {
20 | // Start services on BT connection
21 | if (intent.getAction().compareTo(BluetoothDevice.ACTION_ACL_CONNECTED) == 0) {
22 | Log.i(SdlApplication.TAG, "ACL Connect");
23 | SdlApplication app = SdlApplication.getInstance();
24 | if (app != null) {
25 | Log.i(SdlApplication.TAG, "Starting services");
26 | app.startLocationServices();
27 | app.startWeatherUpdates();
28 | }
29 | }
30 | // Stop services on BT disconnection
31 | else if (intent.getAction().compareTo(BluetoothDevice.ACTION_ACL_DISCONNECTED) == 0) {
32 | Log.i(SdlApplication.TAG, "ACL Disconnect");
33 | SdlApplication app = SdlApplication.getInstance();
34 | if (app != null) {
35 | if (SdlApplication.getCurrentActivity() == null) {
36 | app.stopServices();
37 | }
38 | }
39 | }
40 |
41 | super.onReceive(context, intent);
42 | }
43 |
44 |
45 | @Override
46 | public void onSdlEnabled(Context context, Intent intent) {
47 | //Use the provided intent but set the class to the SdlService
48 | intent.setClass(context, SdlService.class);
49 |
50 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
51 | if (intent.getParcelableExtra(TransportConstants.PENDING_INTENT_EXTRA) != null) {
52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
53 | if (!AndroidTools.hasForegroundServiceTypePermission(context)) {
54 | return;
55 | }
56 | }
57 | PendingIntent pendingIntent = (PendingIntent) intent.getParcelableExtra(TransportConstants.PENDING_INTENT_EXTRA);
58 | try {
59 | //Here we are allowing the RouterService that is in the Foreground to start the SdlService on our behalf
60 | pendingIntent.send(context, 0, intent);
61 | } catch (PendingIntent.CanceledException e) {
62 | e.printStackTrace();
63 | }
64 | }
65 | } else {
66 | // SdlService needs to be foregrounded in Android O and above
67 | // This will prevent apps in the background from crashing when they try to start SdlService
68 | // Because Android O doesn't allow background apps to start background services
69 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
70 | context.startForegroundService(intent);
71 | } else {
72 | context.startService(intent);
73 | }
74 | }
75 | }
76 |
77 |
78 | @Override
79 | public Class extends SdlRouterService> defineLocalSdlRouterClass() {
80 | //Return a local copy of the SdlRouterService located in your project
81 | return com.sdl.mobileweather.smartdevicelink.SdlRouterService.class;
82 | }
83 |
84 | }
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/smartdevicelink/SdlRouterService.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.smartdevicelink;
2 |
3 | public class SdlRouterService extends com.smartdevicelink.transport.SdlRouterService {
4 |
5 |
6 | }
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/AbbreviationDictionary.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import java.util.HashMap;
4 |
5 | import org.xmlpull.v1.XmlPullParser;
6 |
7 | import android.content.Context;
8 | import android.content.res.XmlResourceParser;
9 | import android.util.Log;
10 |
11 | import com.sdl.mobileweather.R;
12 | import com.sdl.mobileweather.smartdevicelink.SdlApplication;
13 |
14 | public class AbbreviationDictionary {
15 |
16 | private static HashMap mAbrvDictionary = null;
17 | private static Object mDictionaryLock = new Object();
18 |
19 | public static String lookUp(String term){
20 | synchronized (mDictionaryLock) {
21 | return mAbrvDictionary.get(term);
22 | }
23 | }
24 |
25 | public static boolean isPrepared(){
26 | synchronized (mDictionaryLock) {
27 | return (mAbrvDictionary != null);
28 | }
29 | }
30 |
31 | public static boolean loadDictionary(Context context){
32 | synchronized (mDictionaryLock) {
33 | XmlResourceParser parser = context.getResources().getXml(R.xml.weather_abrv);
34 | mAbrvDictionary = new HashMap();
35 | String key = null;
36 | String value = null;
37 | try {
38 | int eventType = parser.getEventType();
39 |
40 | while (eventType != XmlPullParser.END_DOCUMENT) {
41 | if (eventType == XmlPullParser.START_DOCUMENT) {
42 |
43 | Log.i(SdlApplication.TAG,
44 | "START_DOCUMENT: Loading abbreviation XML file");
45 | } else if (eventType == XmlPullParser.START_TAG) {
46 | if (parser.getName().equals("entry")) {
47 | Log.d(SdlApplication.TAG, "START_TAG");
48 | key = parser.getAttributeValue(null, "key");
49 | if (key == null) {
50 | parser.close();
51 | break;
52 | }
53 | }
54 | } else if (eventType == XmlPullParser.TEXT) {
55 | if (key != null) {
56 | Log.d(SdlApplication.TAG, "TEXT");
57 | value = parser.getText();
58 | }
59 |
60 | } else if (eventType == XmlPullParser.END_TAG) {
61 | if (parser.getName().equals("entry")) {
62 | mAbrvDictionary.put(key, value);
63 | Log.v(SdlApplication.TAG,
64 | String.format("END_TAG: %s, %s", key, value));
65 | key = null;
66 | value = null;
67 | }
68 | }
69 | eventType = parser.next();
70 | }
71 | } catch (Exception e) {
72 | e.printStackTrace();
73 | Log.d(SdlApplication.TAG,
74 | "Loading exception: mAbrvDictionary=null");
75 | mAbrvDictionary = null;
76 | return false;
77 | }
78 | return true;
79 | }
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/Forecast.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import java.util.Calendar;
4 |
5 | public class Forecast {
6 | public Calendar date;
7 | public String conditionTitle;
8 | public String conditionId;
9 | public Float temperature = (float)0;
10 | public Float highTemperature = (float)0;
11 | public Float lowTemperature = (float)0;
12 | public Float humidity = (float)0;
13 | public Float windSpeed = (float)0;
14 | public Float precipitation = (float)0;
15 | public Integer precipitationChance = 0;
16 | public Float snow = (float)0;
17 | }
18 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/InfoType.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | /**
4 | * Different weather information types that can be displayed.
5 | */
6 | public enum InfoType {
7 | WEATHER_CONDITIONS, HOURLY_FORECAST, STANDARD_FORECAST, DAILY_FORECAST, ALERTS, ROAD_CONDITIONS, NONE, WELCOME_SCREEN;
8 | }
9 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/RoadConditions.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | public enum RoadConditions {
4 | WET, ICE, FOG, WIND, LOW_VISIBILITY, OK
5 | }
6 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/UnitConverter.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | public final class UnitConverter {
4 |
5 | private UnitConverter(){
6 | // Constructor is private to prevent instantiation of static
7 | // method provider
8 | }
9 |
10 | /**
11 | * Convert length from mm to inches.
12 | * @param length
13 | * @return
14 | */
15 | public static float convertLengthToImperial(float length) {
16 | return (float) (length * 0.0393701);
17 | }
18 |
19 | /**
20 | * Convert speed from kph to mph
21 | * @param speed
22 | * @return
23 | */
24 | public static float convertSpeedToImperial(float speed) {
25 | return (float) (speed * 0.621371);
26 | }
27 |
28 | /**
29 | * Convert from Celsius to Fahrenheit.
30 | * @param temperature the temperature in Celsius.
31 | * @return temperature temperature in Fahrenheit.
32 | */
33 | public static float convertTemperatureToImperial(float temperature) {
34 | return (float) ((temperature * 9 / 5) + 32);
35 | }
36 |
37 | /**
38 | * Convert length from inches to mm.
39 | * @param length
40 | * @return
41 | */
42 | public static float convertLengthToMetric(float length) {
43 | return (float) (length / 0.0393701);
44 | }
45 |
46 | /**
47 | * Convert speed from mph to kph
48 | * @param speed
49 | * @return
50 | */
51 | public static float convertSpeedToMetric(float speed) {
52 | return (float) (speed / 0.621371);
53 | }
54 |
55 | /**
56 | * Convert from Fahrenheit to Celsius.
57 | * @param temperature the temperature in Fahrenheit.
58 | * @return temperature temperature in Celsius.
59 | */
60 | public static float convertTemperatureToMetric(float temperature) {
61 | return (float) ((temperature - 32) * 5 / 9);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherAlarmManager.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import android.os.Build;
4 | import java.util.Calendar;
5 |
6 | import android.app.AlarmManager;
7 | import android.app.PendingIntent;
8 | import android.content.BroadcastReceiver;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.IntentFilter;
12 | import android.os.Bundle;
13 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
14 | import android.util.Log;
15 |
16 | import com.sdl.mobileweather.artifact.WeatherLocation;
17 | import com.sdl.mobileweather.smartdevicelink.SdlApplication;
18 |
19 | public class WeatherAlarmManager {
20 |
21 | private static int PENDING_INTENT_ID = 100000;
22 |
23 | private boolean mAlarmRunning = false;
24 | private int mUpdateInterval = 5; // The number of minutes between weather updates
25 | private AlarmManager mAlarmManager = null; // Alarm manager to manage recurring updates
26 | private PendingIntent mAlarmIntent = null; // Intent used to trigger an update
27 | private boolean mFirstLocationUpdate = true; // Used to trigger a manual weather update on the first location update
28 | private WeatherDataManager mDataManager = null;
29 | private Context mAppContext = null;
30 | private Intent mUpdateIntent = null;
31 |
32 | /**
33 | * Receiver
34 | */
35 | private final BroadcastReceiver mChangeUpdateIntervalReceiver = new BroadcastReceiver() {
36 |
37 | @Override
38 | public void onReceive(Context context, Intent intent) {
39 | Log.d(SdlApplication.TAG, "UpdateIntervalReceiver");
40 | if (mAlarmRunning && mDataManager != null) {
41 | mUpdateInterval = mDataManager.getUpdateInterval();
42 | restartAlarm(context);
43 | }
44 | }
45 | };
46 |
47 | /**
48 | * Receiver
49 | */
50 | private final BroadcastReceiver mChangeLocationReceiver = new BroadcastReceiver() {
51 |
52 | @Override
53 | public void onReceive(Context context, Intent intent) {
54 | WeatherLocation currentLocation = null;
55 | String lastCity = null;
56 | String lastState = null;
57 | Log.d("MobileWeather", "WeatherAlarmManager - ChangeLocationReceiver");
58 | if (mDataManager != null) {
59 | currentLocation = mDataManager.getCurrentLocation();
60 | lastCity = mDataManager.getLastCity();
61 | lastState = mDataManager.getLastState();
62 | }
63 | if (mFirstLocationUpdate) {
64 | Log.d("MobileWeather", "WeatherAlarmManager - first location - starting weather update alarm");
65 | restartAlarm(context);
66 | mFirstLocationUpdate = false;
67 | mAppContext.sendBroadcast(mUpdateIntent);
68 | }
69 | else if (currentLocation != null && currentLocation.city != null) {
70 | if((!currentLocation.city.equals(lastCity)) ||
71 | ((currentLocation.state != null) && (!currentLocation.state.equals(lastState)))) {
72 | Log.d("MobileWeather", "city/state change - weather update");
73 | mAppContext.sendBroadcast(mUpdateIntent);
74 | }
75 | }
76 | }
77 | };
78 |
79 | /**
80 | * Receiver
81 | */
82 | private final BroadcastReceiver mRoamingStatusReceiver = new BroadcastReceiver() {
83 |
84 | @Override
85 | public void onReceive(Context context, Intent intent) {
86 | Bundle bundle = intent.getExtras();
87 | if (bundle != null) {
88 | boolean roaming = bundle.getBoolean("roaming");
89 | if (roaming) {
90 | if (mAlarmManager != null && mAlarmIntent != null) {
91 | mAlarmManager.cancel(mAlarmIntent);
92 | mAlarmIntent = null;
93 | mAlarmRunning = false;
94 | }
95 | }
96 | else {
97 | Log.d("MobileWeather", "WeatherAlarmManager - restarting alarm");
98 | restartAlarm(context);
99 | }
100 | }
101 | }
102 | };
103 |
104 | public WeatherAlarmManager(Class> weatherService) {
105 | Log.d(SdlApplication.TAG, "WeatherAlarmManager - constructed");
106 | mAlarmRunning = false;
107 | mDataManager = WeatherDataManager.getInstance();
108 | mAppContext = SdlApplication.getInstance().getApplicationContext();
109 | if (mDataManager != null) {
110 | mUpdateInterval = mDataManager.getUpdateInterval();
111 | }
112 | String weatherServiceName = weatherService.getName();
113 | mUpdateIntent = new Intent(mAppContext, WeatherUpdateWakefulReceiver.class);
114 | mUpdateIntent.putExtra(WeatherUpdateWakefulReceiver.WEATHER_UPDATE_SERVICE, weatherServiceName);
115 | }
116 |
117 | public void startPendingLocation() {
118 | Log.d(SdlApplication.TAG, "WeatherAlarmManager - registering local receivers");
119 | LocalBroadcastManager lbManager = LocalBroadcastManager.getInstance(mAppContext);
120 | lbManager.registerReceiver(mChangeUpdateIntervalReceiver, new IntentFilter("com.sdl.mobileweather.ChangeUpdateInterval"));
121 | lbManager.registerReceiver(mChangeLocationReceiver, new IntentFilter("com.sdl.mobileweather.Location"));
122 | lbManager.registerReceiver(mRoamingStatusReceiver, new IntentFilter("com.sdl.mobileweather.RoamingStatus"));
123 | }
124 |
125 | public void stop() {
126 | Log.d(SdlApplication.TAG, "WeatherAlarmManager - unregistering local receivers");
127 | cancelUpdates();
128 | try {
129 | LocalBroadcastManager lbManager = LocalBroadcastManager.getInstance(mAppContext);
130 | lbManager.unregisterReceiver(mChangeUpdateIntervalReceiver);
131 | lbManager.unregisterReceiver(mChangeLocationReceiver);
132 | lbManager.unregisterReceiver(mRoamingStatusReceiver);
133 |
134 | } catch (IllegalArgumentException e) {
135 | e.printStackTrace();
136 | }
137 | }
138 |
139 | /**
140 | * Stop and cancel any update alarms, and start/restart the timer.
141 | * This is used for periodic weather updates.
142 | */
143 | private void restartAlarm(Context context) {
144 | Log.d(SdlApplication.TAG, "WeatherAlarmManager - restartAlarm");
145 | if (mAlarmManager == null) {
146 | mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
147 | }
148 |
149 | if (mAlarmManager != null && mAlarmIntent != null) {
150 | mAlarmManager.cancel(mAlarmIntent);
151 | }
152 |
153 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
154 | mAlarmIntent = PendingIntent.getBroadcast(context, PENDING_INTENT_ID, mUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
155 | }
156 | else {
157 | mAlarmIntent = PendingIntent.getBroadcast(context, PENDING_INTENT_ID, mUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
158 | }
159 |
160 | Calendar cal = Calendar.getInstance();
161 | cal.setTimeInMillis(System.currentTimeMillis());
162 | cal.add(Calendar.MINUTE, mUpdateInterval);
163 | Log.d(SdlApplication.TAG, "restartAlarm mUpdateInterval = " + mUpdateInterval);
164 |
165 | mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), (mUpdateInterval*60*1000), mAlarmIntent);
166 | mAlarmRunning = true;
167 | }
168 |
169 | /**
170 | * Stop and cancel any update alarm.
171 | */
172 | private void cancelUpdates() {
173 | Log.i(SdlApplication.TAG, "Canceling periodic weather updates..");
174 | if (mAlarmManager != null && mAlarmIntent != null) {
175 | mAlarmManager.cancel(mAlarmIntent);
176 | mAlarmRunning = false;
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherAlert.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import java.util.Calendar;
4 |
5 | public class WeatherAlert {
6 | public WeatherAlertType type;
7 | public String description;
8 | public Calendar dateIssued;
9 | public Calendar dateExpires;
10 | public String message;
11 | }
12 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherAlertType.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | public enum WeatherAlertType {
4 | HUR, TOR, TOW, WRN, SEW, WIN, FLO, WAT, WND, SVR, HEA, FOG, SPE, FIR, VOL, HWW, REC, REP, PUB;
5 | }
6 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherConditions.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | public class WeatherConditions {
4 | public String conditionTitle;
5 | public String conditionId;
6 | public Float temperature;
7 | public Float humidity;
8 | public Float windSpeed;
9 | public Float windSpeedGust;
10 | public Float visibility;
11 | public Float feelsLikeTemperature;
12 | public Float precipitation;
13 | }
14 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherDataManager.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import com.sdl.mobileweather.artifact.WeatherLocation;
4 |
5 | public class WeatherDataManager {
6 |
7 | private static WeatherDataManager instance;
8 |
9 | private WeatherLocation mCurrentLocation = null; // Stores the current location for weather
10 | private String mUnits = null; // Stores the current units
11 | private int mUpdateInterval = 0; // Stores the update interval
12 | private WeatherConditions mWeatherConditions = null; // Stores the current weather conditions
13 | private RoadConditions mRoadConditions = null; // Stores the current road conditions
14 | private WeatherAlert[] mAlerts = null; // Stores the current weather alerts
15 | private Forecast[] mForecast = null; // Stores the current forecast
16 | private Forecast[] mHourlyForecast = null; // Stores the current hourly forecast
17 | private String mLastCity = null; // Stores the city of the last weather update
18 | private String mLastState = null; // Stores the state of the last weather update
19 |
20 | // Locks used for thread safety
21 | private final Object mCurrentLocationLock = new Object();
22 | private final Object mUnitsLock = new Object();
23 | private final Object mUpdateIntervalLock = new Object();
24 | private final Object mWeatherConditionsLock = new Object();
25 | private final Object mRoadConditionsLock = new Object();
26 | private final Object mAlertsLock = new Object();
27 | private final Object mForecastLock = new Object();
28 | private final Object mHourlyForecastLock = new Object();
29 | private final Object mLastCityLock = new Object();
30 | private final Object mLastStateLock = new Object();
31 |
32 | // Error state booleans
33 | private boolean mLocationAvailable = false;
34 | private boolean mAPIAvailable = false;
35 | private boolean mNetworkAvailable = false;
36 |
37 | private final Object mErrorLock = new Object();
38 |
39 | static {
40 | instance = null;
41 | }
42 |
43 | private static synchronized void setInstance(WeatherDataManager man) {
44 | instance = man;
45 | }
46 |
47 | public static synchronized WeatherDataManager getInstance() {
48 | return instance;
49 | }
50 |
51 | public WeatherDataManager() {
52 | WeatherDataManager.setInstance(this);
53 | }
54 |
55 | public WeatherLocation getCurrentLocation() {
56 | synchronized (mCurrentLocationLock) {
57 | return mCurrentLocation;
58 | }
59 | }
60 |
61 | public void setCurrentLocation(WeatherLocation location) {
62 | synchronized (mCurrentLocationLock) {
63 | this.mCurrentLocation = location;
64 | }
65 | }
66 |
67 | public WeatherConditions getWeatherConditions() {
68 | synchronized (mWeatherConditionsLock) {
69 | return mWeatherConditions;
70 | }
71 | }
72 |
73 | public void setWeatherConditions(WeatherConditions conditions) {
74 | synchronized (mWeatherConditionsLock) {
75 | this.mWeatherConditions = conditions;
76 | }
77 | }
78 |
79 | public RoadConditions getRoadConditions() {
80 | synchronized (mRoadConditionsLock) {
81 | return mRoadConditions;
82 | }
83 | }
84 |
85 | public void setRoadConditions(RoadConditions roadConditions) {
86 | synchronized (mRoadConditionsLock) {
87 | this.mRoadConditions = roadConditions;
88 | }
89 | }
90 |
91 | public WeatherAlert[] getAlerts() {
92 | synchronized (mAlertsLock) {
93 | return mAlerts;
94 | }
95 | }
96 |
97 | public void setAlerts(WeatherAlert[] alerts) {
98 | synchronized (mAlertsLock) {
99 | this.mAlerts = alerts;
100 | }
101 | }
102 |
103 | public Forecast[] getForecast() {
104 | synchronized (mForecastLock) {
105 | return mForecast;
106 | }
107 | }
108 |
109 | public void setForecast(Forecast[] forecast) {
110 | synchronized (mForecastLock) {
111 | this.mForecast = forecast;
112 | }
113 | }
114 |
115 | public Forecast[] getHourlyForecast() {
116 | synchronized (mHourlyForecastLock) {
117 | return mHourlyForecast;
118 | }
119 | }
120 |
121 | public void setHourlyForecast(Forecast[] hourlyForecast) {
122 | synchronized (mHourlyForecastLock) {
123 | this.mHourlyForecast = hourlyForecast;
124 | }
125 | }
126 |
127 | public String getUnits() {
128 | synchronized (mUnitsLock) {
129 | return mUnits;
130 | }
131 | }
132 |
133 | public void setUnits(String units) {
134 | synchronized (mUnitsLock) {
135 | this.mUnits = units;
136 | }
137 | }
138 |
139 | public int getUpdateInterval() {
140 | synchronized (mUpdateIntervalLock) {
141 | return mUpdateInterval;
142 | }
143 | }
144 |
145 | public void setUpdateInterval(int mUpdateInterval) {
146 | synchronized (mUpdateIntervalLock) {
147 | this.mUpdateInterval = mUpdateInterval;
148 | }
149 | }
150 |
151 | public String getLastCity() {
152 | synchronized (mLastCityLock) {
153 | return mLastCity;
154 | }
155 | }
156 |
157 | public void setLastCity(String city) {
158 | synchronized (mLastCityLock) {
159 | this.mLastCity = city;
160 | }
161 | }
162 |
163 | public String getLastState() {
164 | synchronized (mLastStateLock) {
165 | return mLastState;
166 | }
167 | }
168 |
169 | public void setLastState(String state) {
170 | synchronized (mLastStateLock) {
171 | this.mLastState = state;
172 | }
173 | }
174 |
175 | public boolean isLocationAvailable() {
176 | synchronized(mErrorLock){
177 | return mLocationAvailable;
178 | }
179 | }
180 |
181 | public void setLocationAvailable(boolean available){
182 | synchronized(mErrorLock){
183 | mLocationAvailable = available;
184 | if(available){
185 | mNetworkAvailable = true;
186 | }
187 | }
188 | }
189 |
190 | public boolean isAPIAvailable() {
191 | synchronized (mErrorLock) {
192 | return mAPIAvailable;
193 | }
194 | }
195 |
196 | public void setAPIAvailable(boolean available) {
197 | synchronized (mErrorLock) {
198 | mAPIAvailable = available;
199 | if(available){
200 | mNetworkAvailable = true;
201 | }
202 | }
203 | }
204 |
205 | public boolean isNetworkAvailable(){
206 | synchronized(mErrorLock){
207 | return mNetworkAvailable;
208 | }
209 | }
210 |
211 | public void setNetworkAvailable(boolean available){
212 | synchronized (mErrorLock){
213 | mNetworkAvailable = available;
214 | }
215 | }
216 |
217 | public boolean isInErrorState(){
218 | synchronized(mErrorLock){
219 | return !(mNetworkAvailable && mAPIAvailable && mLocationAvailable);
220 | }
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherJsonProcessor.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import org.json.JSONObject;
4 |
5 | public interface WeatherJsonProcessor {
6 |
7 | public Forecast[] getForecast(JSONObject forecastJson);
8 | public Forecast[] getHourlyForecast(JSONObject forecastJson);
9 | public WeatherConditions getWeatherConditions(JSONObject conditionsJson);
10 | public WeatherAlert[] getAlerts(JSONObject alertsJson);
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherService.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import java.net.URL;
4 |
5 | import android.app.IntentService;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.net.ConnectivityManager;
9 | import android.net.NetworkInfo;
10 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
11 | import android.util.Log;
12 |
13 | import com.sdl.mobileweather.artifact.WeatherLocation;
14 |
15 | public abstract class WeatherService extends IntentService {
16 |
17 | protected boolean mFirstLocationUpdate = true; // Used to trigger a manual weather update on the first location update
18 | protected WeatherDataManager mDataManager = null;
19 | protected WeatherJsonProcessor mWeatherProcessor = null;
20 |
21 | protected abstract URL[] getURLs(WeatherLocation currentLocation);
22 |
23 | protected abstract void updateWeatherData(URL... urls);
24 |
25 | public WeatherService() {
26 | super("WeatherService");
27 | }
28 |
29 | @Override
30 | protected void onHandleIntent(Intent intent) {
31 |
32 | Log.d("MobileWeather", "WeatherService - Intent recieved");
33 | WeatherLocation currentLocation = null;
34 | mDataManager = WeatherDataManager.getInstance();
35 |
36 | if (mDataManager != null) {
37 | currentLocation = mDataManager.getCurrentLocation();
38 | }
39 |
40 | if (currentLocation != null) {
41 | Log.d("MobileWeather", "WeatherService - valid location");
42 | URL[] weatherURLs = getURLs(currentLocation);
43 | updateWeatherData(weatherURLs);
44 | }
45 |
46 | WeatherUpdateWakefulReceiver.completeWakefulIntent(intent);
47 | }
48 |
49 | protected void reportConnectionAvail(boolean avail){
50 | if(mDataManager != null){
51 | if(mDataManager.isNetworkAvailable() != avail){
52 | ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
53 | NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
54 | boolean isConnected = activeNetwork != null &&
55 | activeNetwork.isConnectedOrConnecting();
56 | mDataManager.setNetworkAvailable(isConnected);
57 | if(!isConnected){
58 | Intent intent = new Intent("com.sdl.mobileweather.ErrorUpdate");
59 | LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
60 | }
61 | }
62 | }
63 | }
64 |
65 | protected void reportApiAvail(boolean avail){
66 | if (mDataManager != null){
67 | if(avail != mDataManager.isAPIAvailable()){
68 | mDataManager.setAPIAvailable(avail);
69 | Intent intent = new Intent("com.sdl.mobileweather.ErrorUpdate");
70 | LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/java/com/sdl/mobileweather/weather/WeatherUpdateWakefulReceiver.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather.weather;
2 |
3 | import com.sdl.mobileweather.smartdevicelink.SdlApplication;
4 |
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import androidx.legacy.content.WakefulBroadcastReceiver;
8 | import android.util.Log;
9 |
10 | public class WeatherUpdateWakefulReceiver extends WakefulBroadcastReceiver {
11 |
12 | protected final static String WEATHER_UPDATE_SERVICE = "weather_update_service";
13 |
14 | @Override
15 | public void onReceive(Context context, Intent intent) {
16 | String className = intent.getStringExtra(WEATHER_UPDATE_SERVICE);
17 | Intent service;
18 | if(className != null){
19 | try {
20 | service = new Intent(context, Class.forName(className));
21 | startWakefulService(context, service);
22 | } catch (ClassNotFoundException e) {
23 | Log.d(SdlApplication.TAG, "WakefulBroadcastReceiver - invalid class name");
24 | e.printStackTrace();
25 | }
26 | }else{
27 | Log.d(SdlApplication.TAG, "WakefulBroadcastReceiver - no service specified");
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/chancesnow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/chancesnow.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/chancesnow_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/chancesnow_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/chancestorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/chancestorm.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/chancestorm_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/chancestorm_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/chancethunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/chancethunderstorm.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/chancethunderstorm_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/chancethunderstorm_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/clearday.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/clearday.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/clearday_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/clearday_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/clearnight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/clearnight.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/clearnight_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/clearnight_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/cloudy.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/cloudy_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/cloudy_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/dusk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/dusk.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/dusk_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/dusk_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/fog.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/fog_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/fog_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/fogcloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/fogcloudy.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/fogcloudy_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/fogcloudy_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/fognight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/fognight.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/fognight_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/fognight_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/ford_oval.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/ford_oval.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/hazy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/hazy.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/hazy_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/hazy_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/ic_drawer.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/icon_license.xml:
--------------------------------------------------------------------------------
1 |
2 |
32 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/lightrain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/lightrain.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/lightrain_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/lightrain_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/lightsnow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/lightsnow.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/lightsnow_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/lightsnow_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudyday.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudyday.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudyday_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudyday_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudynight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudynight.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudynight_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/partlycloudynight_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/partlysunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/partlysunny.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/partlysunny_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/partlysunny_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/powered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/powered.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/rain.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/rain_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/rain_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/sleet.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/sleet_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/sleet_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/snow.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/snow_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/snow_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/snowflake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/snowflake.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/snowflake_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/snowflake_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/storm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/storm.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/storm_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/storm_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/sunrise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/sunrise.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/sunrise_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/sunrise_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/thunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/thunderstorm.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/thunderstorm_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/thunderstorm_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/windy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/windy.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/windy_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/windy_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/windycloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/windycloudy.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/windycloudy_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/windycloudy_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/windyrain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/windyrain.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/windyrain_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/windyrain_50.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-hdpi/wunderground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-hdpi/wunderground.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-mdpi/ic_add_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-mdpi/ic_add_location.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-mdpi/ic_current_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-mdpi/ic_current_location.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-mdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-mdpi/ic_settings.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-xhdpi/ic_add_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-xhdpi/ic_add_location.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-xhdpi/ic_current_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-xhdpi/ic_current_location.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-xhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-xhdpi/ic_settings.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-xxhdpi/ic_add_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-xxhdpi/ic_add_location.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-xxhdpi/ic_current_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-xxhdpi/ic_current_location.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-xxhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-xxhdpi/ic_settings.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_01d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_01d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_01n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_01n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_02d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_02d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_02n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_02n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_03d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_03d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_03n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_03n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_04d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_04d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_04n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_04n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_09d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_09d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_09n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_09n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_10d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_10d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_10n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_10n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_11d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_11d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_11n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_11n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_13d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_13d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_13n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_13n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_50d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_50d.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_50n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_50n.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/drawable/ic_none.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/drawable/ic_none.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
15 |
16 |
17 |
26 |
27 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/drawer_list_item.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/forecast_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
29 |
30 |
39 |
40 |
48 |
49 |
58 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/fragment_alerts.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/fragment_base.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/fragment_conditions.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
29 |
30 |
41 |
42 |
52 |
53 |
63 |
64 |
74 |
75 |
88 |
89 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/fragment_forecast.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/layout/lockscreen.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
22 |
33 |
34 |
35 |
36 |
45 |
46 |
52 |
53 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/menu/alerts.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/menu/forecast.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartDeviceLink-Examples/example_weather_app_android/707d279565e73cb9637863954c1b067571c6ad28/MobileWeather/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values-es-rES/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MobileWeather
5 | Salir
6 | SDL
7 | Ford
8 | Subte
9 | Configurar
10 | MobileWeather
11 | Alertas
12 | Condición Climática
13 | Pronóstico
14 | Abrir Navegador
15 | Cerrar Navegador
16 | "Localizando…"
17 | ---
18 | "Cargando…"
19 | Velocidad del Viento
20 | Humedad
21 | Se Siente Como
22 | "Localizando…"
23 | "Cargando…"
24 | "Información de la versión del Proxy no disponible"
25 | "Información de la versión de MobileWeather no disponible"
26 | "Información de la versión no disponible"
27 | "Versión de Proxy: "
28 | "Versión de App:"
29 | "Versión de MobileWeather: "
30 | metric
31 |
32 |
33 |
34 |
35 | - @string/drawer_item_current_location
36 | - @string/drawer_item_add_location
37 | - @string/drawer_item_settings
38 | - @string/drawer_item_update_weather
39 | - @string/drawer_item_reset_sync
40 | - @string/drawer_item_about
41 |
42 |
43 |
44 | "Ubicación Actual"
45 | "Agregar Ubicación"
46 | "Configurar"
47 | "Actualizar el Clima"
48 | "Resetear el Sync"
49 | "Acerca De"
50 |
51 |
52 | "Unidades Imperiales"
53 | "F"
54 | "MPH"
55 | "Millas por Hora"
56 | "pulgadas"
57 | "Unidades Métricas"
58 | "C"
59 | "KPH"
60 | "Kilómetros por Hora"
61 | "milímetros"
62 |
63 |
64 | "Actual"
65 | "Condicion Actual"
66 |
76 | "daily"
77 | "daily forecast"
78 | "Cambiar Unidade de Medición"
79 | "Unidades"
80 | "Hora a Hora"
81 | "Pronóstico por hora"
82 | "Alertas"
83 | "back"
84 | "today"
85 | "tomorrow"
86 | "Jetzt"
87 |
88 |
89 | "Condición Actual"
90 | "Pronóstico de 3 días"
91 | "Pronóstico de 10 días"
92 | "Daily Forecast"
93 | "Cambiar Unidade de Medición"
94 | "Pronóstico por hora"
95 | "Alertas"
96 | "Back"
97 |
98 |
99 | "Unidades Imperiales"
100 | "Unidades Imperiales"
101 | "Unidades Métricas"
102 | "Unidades Métricas"
103 |
104 |
105 | "Elija la Unidad: Métrica o Imperial"
106 | "Unidades"
107 |
108 |
109 | "No"
110 | "Alertas"
111 | ""
112 | ""
113 | "No se registran alertas por el momoento"
114 |
115 | "hh:mm a"
116 | "%s. Expira en %s ,,"
117 | "Expira en %s"
118 |
119 |
120 |
121 |
122 | "Condiciones"
123 | "No Disponible"
124 | ""
125 | ""
126 | "Condición Actual no disponible"
127 |
128 |
129 | "Pronóstico"
130 | "No Disponible"
131 | ""
132 | ""
133 | "Pronóstico No Disponible"
134 |
135 |
136 | "Sin Red"
137 | "Conexión"
138 | ""
139 | ""
140 | "Conexión de Red no disponible"
141 |
142 |
143 | "Servicio de Localización"
144 | "No Disponible"
145 | ""
146 | ""
147 | "Servicio de Localización no disponible"
148 |
149 |
150 | "API de Clima"
151 | "No Disponible"
152 | ""
153 | ""
154 | "API de Clima no disponible"
155 |
156 |
157 | Actualmente %1$s y hace %2$.0f grados con una humedad de %3$.0f porciento y una velocidad del viento de %4$.0f %5$s
158 | Actualmente %1$s y hace menos %2$.0f grados con una humedad de %3$.0f porciento y una velocidad del viento de %4$.0f %5$s
159 | Cambio en las precipitaciones de %1$d y
160 | En %1$s hará %2$s con %3$s %4$s ,,
161 | %1$s hará %2$s con %3$s %4$s ,,
162 | Temperatura de menos %1$.0f ,,
163 | Temperatura de %1$.0f ,,
164 | Una máxima de menos %1$.0f ,,
165 | Una máxima de %1$.0f ,,
166 | Parcialmente
167 | Mayormente
168 | Ligero
169 | Pesado
170 |
171 |
172 | "dd/MM"
173 | "h a"
174 | "E dd/MM"
175 | "EEEE"
176 | "E"
177 | "M: "
178 | "m: "
179 | "Hora a Hora"
180 |
181 |
182 | "Condicióna Actual, tres días, diez días, cambiar unidad, hora a hora, alerta o presione uno para repetir la información del clima"
183 | "Ayuda de Mobile Weather"
184 |
185 |
186 | "Bienvenido a"
187 | "MobileWeather"
188 | ""
189 | ""
190 | "Bienvenido a MobileWeather"
191 |
192 |
193 | "Actual"
194 | "3 días"
195 |
196 | "Daily"
197 | "Hora a Hora"
198 | "Alertas"
199 | "sb6"
200 | "sb7"
201 | "sb8"
202 |
203 |
204 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values-es-rMX/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MobileWeather
5 | Salir
6 | SDL
7 | Ford
8 | Subte
9 | Configurar
10 | MobileWeather
11 | Alertas
12 | Condición Climática
13 | Pronóstico
14 | Abrir Navegador
15 | Cerrar Navegador
16 | "Localizando…"
17 | ---
18 | "Cargando…"
19 | Velocidad del Viento
20 | Humedad
21 | Se Siente Como
22 | "Localizando…"
23 | "Cargando…"
24 | "Información de la versión del Proxy no disponible"
25 | "Información de la versión de MobileWeather no disponible"
26 | "Información de la versión no disponible"
27 | "Versión de Proxy: "
28 | "Versión de App:"
29 | "Versión de MobileWeather: "
30 | metric
31 |
32 |
33 |
34 |
35 | - @string/drawer_item_current_location
36 | - @string/drawer_item_add_location
37 | - @string/drawer_item_settings
38 | - @string/drawer_item_update_weather
39 | - @string/drawer_item_reset_sync
40 | - @string/drawer_item_about
41 |
42 |
43 |
44 | "Ubicación Actual"
45 | "Agregar Ubicación"
46 | "Configurar"
47 | "Actualizar el Clima"
48 | "Resetear el Sync"
49 | "Acerca De"
50 |
51 |
52 | "Unidades Imperiales"
53 | "F"
54 | "MPH"
55 | "Millas por Hora"
56 | "pulgadas"
57 | "Unidades Métricas"
58 | "C"
59 | "KPH"
60 | "Kilómetros por Hora"
61 | "milímetros"
62 |
63 |
64 | "Actual"
65 | "Condicion Actual"
66 |
76 | "daily"
77 | "daily forecast"
78 | "Cambiar Unidade de Medición"
79 | "Unidades"
80 | "Hora a Hora"
81 | "Pronóstico por hora"
82 | "Alertas"
83 | "back"
84 | "today"
85 | "tomorrow"
86 | "now"
87 |
88 |
89 | "Condición Actual"
90 | "Pronóstico de 3 días"
91 | "Pronóstico de 10 días"
92 | "Daily Forecast"
93 | "Cambiar Unidade de Medición"
94 | "Pronóstico por hora"
95 | "Alertas"
96 | "Back"
97 |
98 |
99 | "Unidades Imperiales"
100 | "Unidades Imperiales"
101 | "Unidades Métricas"
102 | "Unidades Métricas"
103 |
104 |
105 | "Elija la Unidad: Métrica o Imperial"
106 | "Unidades"
107 |
108 |
109 | "No"
110 | "Alertas"
111 | ""
112 | ""
113 | "No se registran alertas por el momoento"
114 |
115 | "hh:mm a"
116 | "%s. Expira en %s ,,"
117 | "Expira en %s"
118 |
119 |
120 |
121 |
122 | "Condiciones"
123 | "No Disponible"
124 | ""
125 | ""
126 | "Condición Actual no disponible"
127 |
128 |
129 | "Pronóstico"
130 | "No Disponible"
131 | ""
132 | ""
133 | "Pronóstico No Disponible"
134 |
135 |
136 | "Sin Red"
137 | "Conexión"
138 | ""
139 | ""
140 | "Conexión de Red no disponible"
141 |
142 |
143 | "Servicio de Localización"
144 | "No Disponible"
145 | ""
146 | ""
147 | "Servicio de Localización no disponible"
148 |
149 |
150 | "API de Clima"
151 | "No Disponible"
152 | ""
153 | ""
154 | "API de Clima no disponible"
155 |
156 |
157 | Actualmente %1$s y hace %2$.0f grados con una humedad de %3$.0f porciento y una velocidad del viento de %4$.0f %5$s
158 | Actualmente %1$s y hace menos %2$.0f grados con una humedad de %3$.0f porciento y una velocidad del viento de %4$.0f %5$s
159 | Cambio en las precipitaciones de %1$d y
160 | En %1$s hará %2$s con %3$s %4$s ,,
161 | %1$s hará %2$s con %3$s %4$s ,,
162 | Temperatura de menos %1$.0f ,,
163 | Temperatura de %1$.0f ,,
164 | Una máxima de menos %1$.0f ,,
165 | Una máxima de %1$.0f ,,
166 | Parcialmente
167 | Mayormente
168 | Ligero
169 | Pesado
170 |
171 |
172 | "dd/MM"
173 | "h a"
174 | "E dd/MM"
175 | "EEEE"
176 | "E"
177 | "M: "
178 | "m: "
179 | "Hora a Hora"
180 |
181 |
182 | "Condicióna Actual, tres días, diez días, cambiar unidad, hora a hora, alerta o presione uno para repetir la información del clima"
183 | "Ayuda de Mobile Weather"
184 |
185 |
186 | "Bienvenido a"
187 | "MobileWeather"
188 | ""
189 | ""
190 | "Bienvenido a MobileWeather"
191 |
192 |
193 | "Actual"
194 | "3 días"
195 |
196 | "Daily"
197 | "Hora a Hora"
198 | "Alertas"
199 | "sb6"
200 | "sb7"
201 | "sb8"
202 |
203 |
204 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values-large/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 8dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MobileWeather
5 | Sair
6 | SDL
7 | Ford
8 | WUnderground
9 | Opções
10 | MobileWeather
11 | Alertas
12 | Condições
13 | Previsão
14 | Abrir navegador
15 | Fechar Navegador
16 | "Obtendo Local.."
17 | ---
18 | "Carregando.."
19 | Velocidade do vento
20 | Umidade
21 | Sensação
22 | "Obtendo Local.."
23 | "Carregando.."
24 | "Versão do Proxy não disponível"
25 | "Versão do MobileWeather não disponível"
26 | "Versão não disponível"
27 | "Versão do Proxy: "
28 | "Versão do App"
29 | "Versão do MobileWeather: "
30 | metric
31 |
32 |
33 |
34 | - @string/drawer_item_current_location
35 | - @string/drawer_item_add_location
36 | - @string/drawer_item_settings
37 | - @string/drawer_item_update_weather
38 | - @string/drawer_item_reset_sync
39 | - @string/drawer_item_about
40 |
41 |
42 |
43 | "Local atual"
44 | "Adicionar local"
45 | "Opções"
46 | "Atualizar Tempo"
47 | "Reiniciar Sync"
48 | "Sobre"
49 |
50 |
51 | "Imperial"
52 | "F"
53 | "MPH"
54 | "milhas por hora"
55 | "polegadas"
56 | "Métrico"
57 | "C"
58 | "km/h"
59 | "kilometros por hora"
60 | "milímetros"
61 |
62 |
63 | "Atual"
64 | "Condições atuais"
65 |
75 | "daily"
76 | "daily forecast"
77 | "Mudar unidades"
78 | "Unidades"
79 | "De hora em hora"
80 | "Previsão horária"
81 | "Alertas"
82 | "back"
83 | "today"
84 | "tomorrow"
85 | "now"
86 |
87 |
88 | "Condições atuais"
89 | "Previsão para 3-dias"
90 | "Previsão para 10-dias"
91 | "Daily Forecast"
92 | "Mudar unidades"
93 | "Previsão horária"
94 | "Alertas"
95 |
96 |
97 |
98 | "Imperial"
99 | "Imperial"
100 | "Métrico"
101 | "Métrico"
102 |
103 |
104 | "Escolha a unidade em métrico ou imperial"
105 | "Unidades"
106 |
107 |
108 | "Não"
109 | "Alertas"
110 | ""
111 | ""
112 | "Nenhum alerta neste período"
113 |
114 | "hh:mm a"
115 | "%s .Expira em %s ,,"
116 | "exp %s"
117 |
118 |
119 | "Condições"
120 | "Não disponíveis"
121 | ""
122 | ""
123 | "Condições atuais não disponíveis"
124 |
125 |
126 | "Previsão"
127 | "Não disponível"
128 | ""
129 | ""
130 | "Previsão não disponível"
131 |
132 |
133 | "Rede indponível"
134 | "Conexão"
135 | ""
136 | ""
137 | "Conexão de rede não disponível"
138 |
139 |
140 | "Serviço local"
141 | "Não disponível"
142 | ""
143 | ""
144 | "Serviço local não disponível"
145 |
146 |
147 | "API de clima"
148 | "Não disponível"
149 | ""
150 | ""
151 | "API de clima não disponível"
152 |
153 |
154 | Tempo atual de %1$s e %2$.0f graus com %3$.0f de humidade percentual, e velocidade do vento de %4$.0f %5$s
155 | Temperatura atual negativa de %1$s e %2$.0f graus com %3$.0f de humidade percentual, e velocidade do vento de %4$.0f %5$s
156 | %1$d porcento de chance de precipitação e
157 | Em %1$s será(ão) %2$s com %3$s %4$s ,,
158 | %1$s será(ão) %2$s com %3$s %4$s ,,
159 | temperatura negativa de %1$.0f,,
160 | temperatura de %1$.0f ,,
161 | uma diminuição de %1$.0f,,
162 | um aumento de %1$.0f ,,
163 | Parcialmente
164 | Maior parte
165 | Leve
166 | Pesado
167 |
168 |
169 | "MM/dd"
170 | "h a"
171 | "E MM/dd"
172 | "EEEE"
173 | "E"
174 | "H: "
175 | "L: "
176 | "De hora em hora"
177 |
178 |
179 | "condições atuais, três dias, dez dias, mudar unidades, De hora em hora, ou alertas, ou pressione um para repetir as informações do tempo"
180 | "ajuda do Mobile Weather"
181 |
182 |
183 | "Bem vindo ao"
184 | "MobileWeather"
185 | ""
186 | ""
187 | "Bem vindo ao Mobile Weather"
188 |
189 |
190 | "Atual"
191 | "3-dias"
192 |
193 | "Daily"
194 | "De hora em hora"
195 | "Alertas"
196 | "sb6"
197 | "sb7"
198 | "sb8"
199 |
200 |
201 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values-pt-rPT/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MobileWeather
5 | Sair
6 | SDL
7 | Ford
8 | WUnderground
9 | Opções
10 | MobileWeather
11 | Alertas
12 | Condições
13 | Previsão
14 | Abrir navegador
15 | Fechar Navegador
16 | "Obtendo Local.."
17 | ---
18 | "Carregando.."
19 | Velocidade do vento
20 | Umidade
21 | Sensação
22 | "Obtendo Local.."
23 | "Carregando.."
24 | "Versão do Proxy não disponível"
25 | "Versão do MobileWeather não disponível"
26 | "Versão não disponível"
27 | "Versão do Proxy: "
28 | "Versão do App"
29 | "Versão do MobileWeather: "
30 | metric
31 |
32 |
33 |
34 | - @string/drawer_item_current_location
35 | - @string/drawer_item_add_location
36 | - @string/drawer_item_settings
37 | - @string/drawer_item_update_weather
38 | - @string/drawer_item_reset_sync
39 | - @string/drawer_item_about
40 |
41 |
42 |
43 | "Local atual"
44 | "Adicionar local"
45 | "Opções"
46 | "Atualizar Tempo"
47 | "Reiniciar Sync"
48 | "Sobre"
49 |
50 |
51 | "Imperial"
52 | "F"
53 | "MPH"
54 | "milhas por hora"
55 | "polegadas"
56 | "Métrico"
57 | "C"
58 | "km/h"
59 | "kilometros por hora"
60 | "milímetros"
61 |
62 |
63 | "Atual"
64 | "Condições atuais"
65 |
75 | "daily"
76 | "daily forecast"
77 | "Mudar unidades"
78 | "Unidades"
79 | "De hora em hora"
80 | "Previsão horária"
81 | "Alertas"
82 | "back"
83 | "today"
84 | "tomorrow"
85 | "now"
86 |
87 |
88 | "Condições atuais"
89 | "Previsão para 3-dias"
90 | "Previsão para 10-dias"
91 | "Daily Forecast"
92 | "Mudar unidades"
93 | "Previsão horária"
94 | "Alertas"
95 | "Back"
96 |
97 |
98 |
99 | "Imperial"
100 | "Imperial"
101 | "Métrico"
102 | "Métrico"
103 |
104 |
105 | "Escolha a unidade em métrico ou imperial"
106 | "Unidades"
107 |
108 |
109 | "Não"
110 | "Alertas"
111 | ""
112 | ""
113 | "Nenhum alerta neste período"
114 |
115 | "hh:mm a"
116 | "%s .Expira em %s ,,"
117 | "exp %s"
118 |
119 |
120 | "Condições"
121 | "Não disponíveis"
122 | ""
123 | ""
124 | "Condições atuais não disponíveis"
125 |
126 |
127 | "Previsão"
128 | "Não disponível"
129 | ""
130 | ""
131 | "Previsão não disponível"
132 |
133 |
134 | "Rede indponível"
135 | "Conexão"
136 | ""
137 | ""
138 | "Conexão de rede não disponível"
139 |
140 |
141 | "Serviço local"
142 | "Não disponível"
143 | ""
144 | ""
145 | "Serviço local não disponível"
146 |
147 |
148 | "API de clima"
149 | "Não disponível"
150 | ""
151 | ""
152 | "API de clima não disponível"
153 |
154 |
155 | Tempo atual de %1$s e %2$.0f graus com %3$.0f de humidade percentual, e velocidade do vento de %4$.0f %5$s
156 | Temperatura atual negativa de %1$s e %2$.0f graus com %3$.0f de humidade percentual, e velocidade do vento de %4$.0f %5$s
157 | %1$d porcento de chance de precipitação e
158 | Em %1$s será(ão) %2$s com %3$s %4$s ,,
159 | %1$s será(ão) %2$s com %3$s %4$s ,,
160 | temperatura negativa de %1$.0f,,
161 | temperatura de %1$.0f ,,
162 | uma diminuição de %1$.0f,,
163 | um aumento de %1$.0f ,,
164 | Parcialmente
165 | Maior parte
166 | Leve
167 | Pesado
168 |
169 |
170 | "MM/dd"
171 | "h a"
172 | "E MM/dd"
173 | "EEEE"
174 | "E"
175 | "H: "
176 | "L: "
177 | "De hora em hora"
178 |
179 |
180 | "condições atuais, três dias, dez dias, mudar unidades, De hora em hora, ou alertas, ou pressione um para repetir as informações do tempo"
181 | "ajuda do Mobile Weather"
182 |
183 |
184 | "Bem vindo ao"
185 | "MobileWeather"
186 | ""
187 | ""
188 | "Bem vindo ao Mobile Weather"
189 |
190 |
191 | "Atual"
192 | "3-dias"
193 |
194 | "Daily"
195 | "De hora em hora"
196 | "Alertas"
197 | "sb6"
198 | "sb7"
199 | "sb8"
200 |
201 |
202 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #fff3f3f3
8 | #212121
9 | #39609A
10 | #F4F4F7
11 | #F4F4F7
12 |
13 |
14 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 8dp
5 | 8dp
6 | 16dp
7 | 24dp
8 | 16dp
9 | 16dp
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #39609A
4 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/main/res/xml/weather_abrv.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/MobileWeather/app/src/test/java/com/sdl/mobileweather/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.sdl.mobileweather;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/MobileWeather/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | mavenCentral()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:7.4.2'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | mavenCentral()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/MobileWeather/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | android.enableJetifier=true
10 | android.useAndroidX=true
11 | org.gradle.jvmargs=-Xmx1536m
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 |
--------------------------------------------------------------------------------
/MobileWeather/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Apr 12 09:43:03 EDT 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
7 |
--------------------------------------------------------------------------------
/MobileWeather/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/MobileWeather/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/MobileWeather/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android Mobile Weather Tutorial
2 |
3 | This tutorial is designed to show you how to include the SmartDeviceLink SDK in your app and to help you get your app’s features onto the vehicle’s infotainment head unit.
4 |
5 | Please visit the [wiki](https://github.com/smartdevicelink/sdl_mobileweather_tutorial_android/wiki) of this repository to get the full tutorial.
6 |
7 | ### Weather API Key
8 |
9 | 1. Sign up and get your own [OpenWeather API Key](https://home.openweathermap.org/api_keys).
10 | 2. Set the value of `API_KEY`in `OpenWeatherMapService.java` to your API key
11 |
--------------------------------------------------------------------------------