├── .gitignore ├── CODEOWNERS ├── CONTRIB.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── android │ │ └── sunshine │ │ └── app │ │ ├── FullTestSuite.java │ │ ├── data │ │ ├── TestDb.java │ │ ├── TestProvider.java │ │ ├── TestUriMatcher.java │ │ ├── TestUtilities.java │ │ └── TestWeatherContract.java │ │ └── utils │ │ └── PollingCheck.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── android │ │ └── sunshine │ │ └── app │ │ ├── DetailActivity.java │ │ ├── DetailFragment.java │ │ ├── ForecastAdapter.java │ │ ├── ForecastFragment.java │ │ ├── ItemChoiceManager.java │ │ ├── LocationEditTextPreference.java │ │ ├── MainActivity.java │ │ ├── SettingsActivity.java │ │ ├── Utility.java │ │ ├── data │ │ ├── WeatherContract.java │ │ ├── WeatherDbHelper.java │ │ └── WeatherProvider.java │ │ ├── gcm │ │ ├── MyGcmListenerService.java │ │ ├── MyInstanceIDListenerService.java │ │ └── RegistrationIntentService.java │ │ ├── muzei │ │ └── WeatherMuzeiSource.java │ │ ├── sync │ │ ├── SunshineAuthenticator.java │ │ ├── SunshineAuthenticatorService.java │ │ ├── SunshineSyncAdapter.java │ │ └── SunshineSyncService.java │ │ └── widget │ │ ├── DetailWidgetProvider.java │ │ ├── DetailWidgetRemoteViewsService.java │ │ ├── TodayWidgetIntentService.java │ │ └── TodayWidgetProvider.java │ └── res │ ├── drawable-hdpi-v11 │ └── ic_status.png │ ├── drawable-hdpi │ ├── art_clear.png │ ├── art_clouds.png │ ├── art_fog.png │ ├── art_light_clouds.png │ ├── art_light_rain.png │ ├── art_rain.png │ ├── art_snow.png │ ├── art_storm.png │ ├── ic_clear.png │ ├── ic_cloudy.png │ ├── ic_current_location.png │ ├── ic_fog.png │ ├── ic_light_clouds.png │ ├── ic_light_rain.png │ ├── ic_logo.png │ ├── ic_rain.png │ ├── ic_snow.png │ ├── ic_status.png │ └── ic_storm.png │ ├── drawable-mdpi-v11 │ └── ic_status.png │ ├── drawable-mdpi │ ├── art_clear.png │ ├── art_clouds.png │ ├── art_fog.png │ ├── art_light_clouds.png │ ├── art_light_rain.png │ ├── art_rain.png │ ├── art_snow.png │ ├── art_storm.png │ ├── ic_clear.png │ ├── ic_cloudy.png │ ├── ic_current_location.png │ ├── ic_fog.png │ ├── ic_light_clouds.png │ ├── ic_light_rain.png │ ├── ic_logo.png │ ├── ic_rain.png │ ├── ic_snow.png │ ├── ic_status.png │ └── ic_storm.png │ ├── drawable-nodpi │ ├── ic_muzei.png │ ├── widget_preview_detail.png │ └── widget_preview_today.png │ ├── drawable-v21 │ ├── today_touch_selector.xml │ ├── touch_selector.xml │ ├── touch_selector_activated.xml │ ├── touch_selector_base.xml │ └── touch_selector_white.xml │ ├── drawable-xhdpi-v11 │ └── ic_status.png │ ├── drawable-xhdpi │ ├── art_clear.png │ ├── art_clouds.png │ ├── art_fog.png │ ├── art_light_clouds.png │ ├── art_light_rain.png │ ├── art_rain.png │ ├── art_snow.png │ ├── art_storm.png │ ├── ic_clear.png │ ├── ic_cloudy.png │ ├── ic_current_location.png │ ├── ic_fog.png │ ├── ic_light_clouds.png │ ├── ic_light_rain.png │ ├── ic_logo.png │ ├── ic_rain.png │ ├── ic_snow.png │ ├── ic_status.png │ └── ic_storm.png │ ├── drawable-xxhdpi-v11 │ └── ic_status.png │ ├── drawable-xxhdpi │ ├── art_clear.png │ ├── art_clouds.png │ ├── art_fog.png │ ├── art_light_clouds.png │ ├── art_light_rain.png │ ├── art_rain.png │ ├── art_snow.png │ ├── art_storm.png │ ├── ic_clear.png │ ├── ic_cloudy.png │ ├── ic_current_location.png │ ├── ic_fog.png │ ├── ic_light_clouds.png │ ├── ic_light_rain.png │ ├── ic_logo.png │ ├── ic_rain.png │ ├── ic_snow.png │ ├── ic_status.png │ ├── ic_storm.png │ └── mipmap │ │ └── ic_launcher.png │ ├── drawable │ ├── today_touch_selector.xml │ ├── touch_selector.xml │ ├── touch_selector_activated.xml │ └── touch_selector_white.xml │ ├── layout-land │ ├── fragment_main.xml │ └── list_item_forecast_today.xml │ ├── layout-sw600dp-port │ └── activity_main.xml │ ├── layout-sw600dp │ ├── activity_main.xml │ └── fragment_main.xml │ ├── layout │ ├── activity_detail.xml │ ├── activity_main.xml │ ├── detail_extras_grid.xml │ ├── detail_today_grid.xml │ ├── fragment_detail.xml │ ├── fragment_detail_twopane.xml │ ├── fragment_detail_wide.xml │ ├── fragment_main.xml │ ├── fragment_main_base.xml │ ├── list_item_base_forecast_today.xml │ ├── list_item_forecast.xml │ ├── list_item_forecast_today.xml │ ├── pref_current_location.xml │ ├── widget_detail.xml │ ├── widget_detail_list_item.xml │ ├── widget_today.xml │ ├── widget_today_large.xml │ └── widget_today_small.xml │ ├── menu │ ├── detail.xml │ ├── detailfragment.xml │ ├── forecastfragment.xml │ └── main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── transition-land-v21 │ ├── details_window_enter_transition.xml │ └── details_window_return_transition.xml │ ├── transition-v21 │ ├── details_window_enter_transition.xml │ └── details_window_return_transition.xml │ ├── values-land │ └── refs.xml │ ├── values-sw600dp-land │ └── refs.xml │ ├── values-sw600dp-port │ └── dimens.xml │ ├── values-sw600dp │ ├── bools.xml │ ├── dimens.xml │ ├── refs.xml │ └── styles.xml │ ├── values-sw720dp-port │ └── dimens.xml │ ├── values-sw720dp │ └── dimens.xml │ ├── values-v11 │ └── bools.xml │ ├── values-v14 │ ├── styles.xml │ └── widget_dimens.xml │ ├── values-v21 │ └── styles.xml │ ├── values │ ├── arrays.xml │ ├── attrs.xml │ ├── bools.xml │ ├── colors.xml │ ├── dimens.xml │ ├── refs.xml │ ├── strings.xml │ ├── styles.xml │ └── widget_dimens.xml │ └── xml │ ├── authenticator.xml │ ├── pref_general.xml │ ├── syncadapter.xml │ ├── widget_info_detail.xml │ └── widget_info_today.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .DS_Store 3 | 4 | # built application files 5 | *.apk 6 | *.ap_ 7 | 8 | # files for the dex VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # generated files 15 | bin/ 16 | out/ 17 | gen/ 18 | 19 | # Libraries used by the app 20 | # Can explicitly add if we want, but shouldn't do so blindly. Licenses, bloat, etc. 21 | /libs 22 | 23 | 24 | # Build stuff (auto-generated by android update project ...) 25 | build.xml 26 | ant.properties 27 | local.properties 28 | project.properties 29 | 30 | # Eclipse project files 31 | .classpath 32 | .project 33 | 34 | # idea project files 35 | .idea/ 36 | .idea/.name 37 | *.iml 38 | *.ipr 39 | *.iws 40 | 41 | ##Gradle-based build 42 | .gradle 43 | build/ 44 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @udacity/active-public-content -------------------------------------------------------------------------------- /CONTRIB.md: -------------------------------------------------------------------------------- 1 | # How to become a contributor and submit your own code 2 | 3 | ## Contributor License Agreements 4 | 5 | We'd love to accept your sample apps and patches! Before we can take them, we 6 | have to jump a couple of legal hurdles. 7 | 8 | Please fill out either the individual or corporate Contributor License Agreement (CLA). 9 | 10 | * If you are an individual writing original source code and you're sure you 11 | own the intellectual property, then you'll need to sign an [individual CLA] 12 | (https://developers.google.com/open-source/cla/individual). 13 | * If you work for a company that wants to allow you to contribute your work, 14 | then you'll need to sign a [corporate CLA] 15 | (https://developers.google.com/open-source/cla/corporate). 16 | 17 | Follow either of the two links above to access the appropriate CLA and 18 | instructions for how to sign and return it. Once we receive it, we'll be able to 19 | accept your pull requests. 20 | 21 | ## Contributing A Patch 22 | 23 | 1. Submit an issue describing your proposed change to the repo in question. 24 | 2. The repo owner will respond to your issue promptly. 25 | 3. If your proposed change is accepted, and you haven't already done so, sign a 26 | Contributor License Agreement (see details above). 27 | 4. Fork the desired repo, develop and test your code changes. 28 | 5. Ensure that your code adheres to the existing style in the sample to which 29 | you are contributing. Refer to the 30 | [Android Code Style Guide] 31 | (https://source.android.com/source/code-style.html) for the 32 | recommended coding standards for this organization. 33 | 6. Ensure that your code has an appropriate set of unit tests which all pass. 34 | 7. Submit a pull request. 35 | 36 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to become a contributor and submit your own code 2 | 3 | ## Contributor License Agreements 4 | 5 | We'd love to accept your sample apps and patches! Before we can take them, we 6 | have to jump a couple of legal hurdles. 7 | 8 | Please fill out either the individual or corporate Contributor License Agreement (CLA). 9 | 10 | * If you are an individual writing original source code and you're sure you 11 | own the intellectual property, then you'll need to sign an [individual CLA] 12 | (https://cla.developers.google.com). 13 | * If you work for a company that wants to allow you to contribute your work, 14 | then you'll need to sign a [corporate CLA] 15 | (https://cla.developers.google.com). 16 | 17 | Follow either of the two links above to access the appropriate CLA and 18 | instructions for how to sign and return it. Once we receive it, we'll be able to 19 | accept your pull requests. 20 | 21 | ## Contributing A Patch 22 | 23 | 1. Submit an issue describing your proposed change to the repo in question. 24 | 2. The repo owner will respond to your issue promptly. 25 | 3. If your proposed change is accepted, and you haven't already done so, sign a 26 | Contributor License Agreement (see details above). 27 | 4. Fork the desired repo, develop and test your code changes. 28 | 5. Ensure that your code adheres to the existing style in the sample to which 29 | you are contributing. Refer to the 30 | [Android Code Style Guide] 31 | (https://source.android.com/source/code-style.html) for the 32 | recommended coding standards for this organization. 33 | 6. Ensure that your code has an appropriate set of unit tests which all pass. 34 | 7. Submit a pull request. 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Advanced Android Sample App 2 | =================================== 3 | 4 | Synchronizes weather information from OpenWeatherMap on Android Phones and Tablets. Used in the Udacity Advanced Android course. 5 | 6 | Pre-requisites 7 | -------------- 8 | Android SDK 21 or Higher 9 | Build Tools version 21.1.2 10 | Android Support AppCompat 22.2.0 11 | Android Support Annotations 22.2.0 12 | Android Support GridLayout 22.2.0 13 | Android Support CardView 22.2.0 14 | Android Support Design 22.2.0 15 | Android Support RecyclerView 22.2.0 16 | Google Play Services GCM 7.0.0 17 | BumpTech Glide 3.5.2 18 | 19 | 20 | Getting Started 21 | --------------- 22 | This sample uses the Gradle build system. To build this project, use the 23 | "gradlew build" command or use "Import Project" in Android Studio. 24 | 25 | Support 26 | ------- 27 | 28 | - Google+ Community: https://plus.google.com/communities/105153134372062985968 29 | - Stack Overflow: http://stackoverflow.com/questions/tagged/android 30 | 31 | Patches are encouraged, and may be submitted by forking this project and 32 | submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details. 33 | 34 | License 35 | ------- 36 | Copyright 2015 The Android Open Source Project, Inc. 37 | 38 | Licensed to the Apache Software Foundation (ASF) under one or more contributor 39 | license agreements. See the NOTICE file distributed with this work for 40 | additional information regarding copyright ownership. The ASF licenses this 41 | file to you under the Apache License, Version 2.0 (the "License"); you may not 42 | use this file except in compliance with the License. You may obtain a copy of 43 | the License at 44 | 45 | http://www.apache.org/licenses/LICENSE-2.0 46 | 47 | Unless required by applicable law or agreed to in writing, software 48 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 49 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 50 | License for the specific language governing permissions and limitations under 51 | the License. 52 | 53 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.google.gms.google-services' 3 | 4 | android { 5 | compileSdkVersion 21 6 | buildToolsVersion "21.1.2" 7 | 8 | defaultConfig { 9 | applicationId "com.example.android.sunshine.app" 10 | minSdkVersion 10 11 | targetSdkVersion 21 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | buildTypes.each { 22 | it.buildConfigField 'String', 'OPEN_WEATHER_MAP_API_KEY', MyOpenWeatherMapApiKey 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | compile 'com.github.bumptech.glide:glide:3.5.2' 29 | compile 'com.android.support:support-annotations:22.2.0' 30 | compile 'com.android.support:gridlayout-v7:22.2.0' 31 | compile 'com.android.support:cardview-v7:22.2.0' 32 | compile 'com.android.support:appcompat-v7:22.2.0' 33 | compile 'com.android.support:design:22.2.0' 34 | compile 'com.android.support:recyclerview-v7:22.2.0' 35 | compile 'com.google.android.apps.muzei:muzei-api:2.0' 36 | compile 'com.google.android.gms:play-services-gcm:7.5.0' 37 | compile 'com.google.android.gms:play-services-location:7.5.0' 38 | } 39 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/lyla/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/android/sunshine/app/FullTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app; 17 | 18 | import android.test.suitebuilder.TestSuiteBuilder; 19 | 20 | import junit.framework.Test; 21 | import junit.framework.TestSuite; 22 | 23 | public class FullTestSuite extends TestSuite { 24 | public static Test suite() { 25 | return new TestSuiteBuilder(FullTestSuite.class) 26 | .includeAllPackagesUnderHere().build(); 27 | } 28 | 29 | public FullTestSuite() { 30 | super(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/android/sunshine/app/data/TestUriMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app.data; 17 | 18 | import android.content.UriMatcher; 19 | import android.net.Uri; 20 | import android.test.AndroidTestCase; 21 | 22 | /* 23 | Uncomment this class when you are ready to test your UriMatcher. Note that this class utilizes 24 | constants that are declared with package protection inside of the UriMatcher, which is why 25 | the test must be in the same data package as the Android app code. Doing the test this way is 26 | a nice compromise between data hiding and testability. 27 | */ 28 | public class TestUriMatcher extends AndroidTestCase { 29 | private static final String LOCATION_QUERY = "London, UK"; 30 | private static final long TEST_DATE = 1419033600L; // December 20th, 2014 31 | private static final long TEST_LOCATION_ID = 10L; 32 | 33 | // content://com.example.android.sunshine.app/weather" 34 | private static final Uri TEST_WEATHER_DIR = WeatherContract.WeatherEntry.CONTENT_URI; 35 | private static final Uri TEST_WEATHER_WITH_LOCATION_DIR = WeatherContract.WeatherEntry.buildWeatherLocation(LOCATION_QUERY); 36 | private static final Uri TEST_WEATHER_WITH_LOCATION_AND_DATE_DIR = WeatherContract.WeatherEntry.buildWeatherLocationWithDate(LOCATION_QUERY, TEST_DATE); 37 | // content://com.example.android.sunshine.app/location" 38 | private static final Uri TEST_LOCATION_DIR = WeatherContract.LocationEntry.CONTENT_URI; 39 | 40 | /* 41 | Students: This function tests that your UriMatcher returns the correct integer value 42 | for each of the Uri types that our ContentProvider can handle. Uncomment this when you are 43 | ready to test your UriMatcher. 44 | */ 45 | public void testUriMatcher() { 46 | UriMatcher testMatcher = WeatherProvider.buildUriMatcher(); 47 | 48 | assertEquals("Error: The WEATHER URI was matched incorrectly.", 49 | testMatcher.match(TEST_WEATHER_DIR), WeatherProvider.WEATHER); 50 | assertEquals("Error: The WEATHER WITH LOCATION URI was matched incorrectly.", 51 | testMatcher.match(TEST_WEATHER_WITH_LOCATION_DIR), WeatherProvider.WEATHER_WITH_LOCATION); 52 | assertEquals("Error: The WEATHER WITH LOCATION AND DATE URI was matched incorrectly.", 53 | testMatcher.match(TEST_WEATHER_WITH_LOCATION_AND_DATE_DIR), WeatherProvider.WEATHER_WITH_LOCATION_AND_DATE); 54 | assertEquals("Error: The LOCATION URI was matched incorrectly.", 55 | testMatcher.match(TEST_LOCATION_DIR), WeatherProvider.LOCATION); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/android/sunshine/app/data/TestWeatherContract.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app.data; 17 | 18 | import android.net.Uri; 19 | import android.test.AndroidTestCase; 20 | 21 | /* 22 | Students: This is NOT a complete test for the WeatherContract --- just for the functions 23 | that we expect you to write. 24 | */ 25 | public class TestWeatherContract extends AndroidTestCase { 26 | 27 | // intentionally includes a slash to make sure Uri is getting quoted correctly 28 | private static final String TEST_WEATHER_LOCATION = "/North Pole"; 29 | private static final long TEST_WEATHER_DATE = 1419033600L; // December 20th, 2014 30 | 31 | /* 32 | Students: Uncomment this out to test your weather location function. 33 | */ 34 | public void testBuildWeatherLocation() { 35 | Uri locationUri = WeatherContract.WeatherEntry.buildWeatherLocation(TEST_WEATHER_LOCATION); 36 | assertNotNull("Error: Null Uri returned. You must fill-in buildWeatherLocation in " + 37 | "WeatherContract.", 38 | locationUri); 39 | assertEquals("Error: Weather location not properly appended to the end of the Uri", 40 | TEST_WEATHER_LOCATION, locationUri.getLastPathSegment()); 41 | assertEquals("Error: Weather location Uri doesn't match our expected result", 42 | locationUri.toString(), 43 | "content://com.example.android.sunshine.app/weather/%2FNorth%20Pole"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/android/sunshine/app/utils/PollingCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Note: This file copied from the Android CTS Tests 17 | */ 18 | package com.example.android.sunshine.app.utils; 19 | 20 | import junit.framework.Assert; 21 | 22 | import java.util.concurrent.Callable; 23 | 24 | public abstract class PollingCheck { 25 | private static final long TIME_SLICE = 50; 26 | private long mTimeout = 3000; 27 | 28 | public PollingCheck() { 29 | } 30 | 31 | public PollingCheck(long timeout) { 32 | mTimeout = timeout; 33 | } 34 | 35 | protected abstract boolean check(); 36 | 37 | public void run() { 38 | if (check()) { 39 | return; 40 | } 41 | 42 | long timeout = mTimeout; 43 | while (timeout > 0) { 44 | try { 45 | Thread.sleep(TIME_SLICE); 46 | } catch (InterruptedException e) { 47 | Assert.fail("unexpected InterruptedException"); 48 | } 49 | 50 | if (check()) { 51 | return; 52 | } 53 | 54 | timeout -= TIME_SLICE; 55 | } 56 | 57 | Assert.fail("unexpected timeout"); 58 | } 59 | 60 | public static void check(CharSequence message, long timeout, Callable condition) 61 | throws Exception { 62 | while (timeout > 0) { 63 | if (condition.call()) { 64 | return; 65 | } 66 | 67 | Thread.sleep(TIME_SLICE); 68 | timeout -= TIME_SLICE; 69 | } 70 | 71 | Assert.fail(message.toString()); 72 | } 73 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/DetailActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app; 17 | 18 | import android.content.Intent; 19 | import android.os.Build; 20 | import android.os.Bundle; 21 | import android.support.v7.app.ActionBarActivity; 22 | import android.support.v7.app.AppCompatActivity; 23 | import android.support.v7.widget.Toolbar; 24 | import android.view.Menu; 25 | import android.view.MenuItem; 26 | 27 | 28 | public class DetailActivity extends AppCompatActivity { 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_detail); 34 | 35 | if (savedInstanceState == null) { 36 | // Create the detail fragment and add it to the activity 37 | // using a fragment transaction. 38 | 39 | Bundle arguments = new Bundle(); 40 | arguments.putParcelable(DetailFragment.DETAIL_URI, getIntent().getData()); 41 | arguments.putBoolean(DetailFragment.DETAIL_TRANSITION_ANIMATION, true); 42 | 43 | DetailFragment fragment = new DetailFragment(); 44 | fragment.setArguments(arguments); 45 | 46 | getSupportFragmentManager().beginTransaction() 47 | .add(R.id.weather_detail_container, fragment) 48 | .commit(); 49 | 50 | // Being here means we are in animation mode 51 | supportPostponeEnterTransition(); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/LocationEditTextPreference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app; 17 | 18 | import android.app.Activity; 19 | import android.app.AlertDialog; 20 | import android.app.Dialog; 21 | import android.content.Context; 22 | import android.content.res.TypedArray; 23 | import android.os.Bundle; 24 | import android.preference.EditTextPreference; 25 | import android.text.Editable; 26 | import android.text.TextWatcher; 27 | import android.util.AttributeSet; 28 | import android.view.View; 29 | import android.view.ViewGroup; 30 | import android.widget.Button; 31 | import android.widget.EditText; 32 | 33 | import com.google.android.gms.common.ConnectionResult; 34 | import com.google.android.gms.common.GoogleApiAvailability; 35 | import com.google.android.gms.common.GooglePlayServicesNotAvailableException; 36 | import com.google.android.gms.common.GooglePlayServicesRepairableException; 37 | import com.google.android.gms.location.places.ui.PlacePicker; 38 | 39 | public class LocationEditTextPreference extends EditTextPreference { 40 | static final private int DEFAULT_MINIMUM_LOCATION_LENGTH = 2; 41 | private int mMinLength; 42 | 43 | public LocationEditTextPreference(Context context, AttributeSet attrs) { 44 | super(context, attrs); 45 | TypedArray a = context.getTheme().obtainStyledAttributes( 46 | attrs, 47 | R.styleable.LocationEditTextPreference, 48 | 0, 0); 49 | try { 50 | mMinLength = a.getInteger(R.styleable.LocationEditTextPreference_minLength, DEFAULT_MINIMUM_LOCATION_LENGTH); 51 | } finally { 52 | a.recycle(); 53 | } 54 | 55 | // Check to see if Google Play services is available. The Place Picker API is available 56 | // through Google Play services, so if this is false, we'll just carry on as though this 57 | // feature does not exist. If it is true, however, we can add a widget to our preference. 58 | GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); 59 | int resultCode = apiAvailability.isGooglePlayServicesAvailable(getContext()); 60 | if (resultCode == ConnectionResult.SUCCESS) { 61 | // Add the get current location widget to our location preference 62 | setWidgetLayoutResource(R.layout.pref_current_location); 63 | } 64 | } 65 | 66 | @Override 67 | protected View onCreateView(ViewGroup parent) { 68 | View view = super.onCreateView(parent); 69 | View currentLocation = view.findViewById(R.id.current_location); 70 | currentLocation.setOnClickListener(new View.OnClickListener() { 71 | @Override 72 | public void onClick(View v) { 73 | Context context = getContext(); 74 | 75 | // Launch the Place Picker so that the user can specify their location, and then 76 | // return the result to SettingsActivity. 77 | PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); 78 | 79 | 80 | // We are in a view right now, not an activity. So we need to get ourselves 81 | // an activity that we can use to start our Place Picker intent. By using 82 | // SettingsActivity in this way, we can ensure the result of the Place Picker 83 | // intent comes to the right place for us to process it. 84 | Activity settingsActivity = (SettingsActivity) context; 85 | try { 86 | settingsActivity.startActivityForResult( 87 | builder.build(context), SettingsActivity.PLACE_PICKER_REQUEST); 88 | 89 | } catch (GooglePlayServicesNotAvailableException 90 | | GooglePlayServicesRepairableException e) { 91 | // What did you do?? This is why we check Google Play services in onResume!!! 92 | // The difference in these exception types is the difference between pausing 93 | // for a moment to prompt the user to update/install/enable Play services vs 94 | // complete and utter failure. 95 | // If you prefer to manage Google Play services dynamically, then you can do so 96 | // by responding to these exceptions in the right moment. But I prefer a cleaner 97 | // user experience, which is why you check all of this when the app resumes, 98 | // and then disable/enable features based on that availability. 99 | } 100 | } 101 | }); 102 | 103 | return view; 104 | } 105 | 106 | @Override 107 | protected void showDialog(Bundle state) { 108 | super.showDialog(state); 109 | 110 | EditText et = getEditText(); 111 | et.addTextChangedListener(new TextWatcher() { 112 | 113 | 114 | @Override 115 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 116 | 117 | } 118 | 119 | @Override 120 | public void onTextChanged(CharSequence s, int start, int before, int count) { 121 | 122 | } 123 | 124 | @Override 125 | public void afterTextChanged(Editable s) { 126 | Dialog d = getDialog(); 127 | if (d instanceof AlertDialog) { 128 | AlertDialog dialog = (AlertDialog) d; 129 | Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE); 130 | // Check if the EditText is empty 131 | if (s.length() < mMinLength) { 132 | // Disable OK button 133 | positiveButton.setEnabled(false); 134 | } else { 135 | // Re-enable the button. 136 | positiveButton.setEnabled(true); 137 | } 138 | } 139 | } 140 | }); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/data/WeatherDbHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app.data; 17 | 18 | import android.content.Context; 19 | import android.database.sqlite.SQLiteDatabase; 20 | import android.database.sqlite.SQLiteOpenHelper; 21 | 22 | import com.example.android.sunshine.app.data.WeatherContract.LocationEntry; 23 | import com.example.android.sunshine.app.data.WeatherContract.WeatherEntry; 24 | 25 | /** 26 | * Manages a local database for weather data. 27 | */ 28 | public class WeatherDbHelper extends SQLiteOpenHelper { 29 | 30 | // If you change the database schema, you must increment the database version. 31 | private static final int DATABASE_VERSION = 2; 32 | 33 | static final String DATABASE_NAME = "weather.db"; 34 | 35 | public WeatherDbHelper(Context context) { 36 | super(context, DATABASE_NAME, null, DATABASE_VERSION); 37 | } 38 | 39 | @Override 40 | public void onCreate(SQLiteDatabase sqLiteDatabase) { 41 | // Create a table to hold locations. A location consists of the string supplied in the 42 | // location setting, the city name, and the latitude and longitude 43 | final String SQL_CREATE_LOCATION_TABLE = "CREATE TABLE " + LocationEntry.TABLE_NAME + " (" + 44 | LocationEntry._ID + " INTEGER PRIMARY KEY," + 45 | LocationEntry.COLUMN_LOCATION_SETTING + " TEXT UNIQUE NOT NULL, " + 46 | LocationEntry.COLUMN_CITY_NAME + " TEXT NOT NULL, " + 47 | LocationEntry.COLUMN_COORD_LAT + " REAL NOT NULL, " + 48 | LocationEntry.COLUMN_COORD_LONG + " REAL NOT NULL " + 49 | " );"; 50 | 51 | final String SQL_CREATE_WEATHER_TABLE = "CREATE TABLE " + WeatherEntry.TABLE_NAME + " (" + 52 | // Why AutoIncrement here, and not above? 53 | // Unique keys will be auto-generated in either case. But for weather 54 | // forecasting, it's reasonable to assume the user will want information 55 | // for a certain date and all dates *following*, so the forecast data 56 | // should be sorted accordingly. 57 | WeatherEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 58 | 59 | // the ID of the location entry associated with this weather data 60 | WeatherEntry.COLUMN_LOC_KEY + " INTEGER NOT NULL, " + 61 | WeatherEntry.COLUMN_DATE + " INTEGER NOT NULL, " + 62 | WeatherEntry.COLUMN_SHORT_DESC + " TEXT NOT NULL, " + 63 | WeatherEntry.COLUMN_WEATHER_ID + " INTEGER NOT NULL," + 64 | 65 | WeatherEntry.COLUMN_MIN_TEMP + " REAL NOT NULL, " + 66 | WeatherEntry.COLUMN_MAX_TEMP + " REAL NOT NULL, " + 67 | 68 | WeatherEntry.COLUMN_HUMIDITY + " REAL NOT NULL, " + 69 | WeatherEntry.COLUMN_PRESSURE + " REAL NOT NULL, " + 70 | WeatherEntry.COLUMN_WIND_SPEED + " REAL NOT NULL, " + 71 | WeatherEntry.COLUMN_DEGREES + " REAL NOT NULL, " + 72 | 73 | // Set up the location column as a foreign key to location table. 74 | " FOREIGN KEY (" + WeatherEntry.COLUMN_LOC_KEY + ") REFERENCES " + 75 | LocationEntry.TABLE_NAME + " (" + LocationEntry._ID + "), " + 76 | 77 | // To assure the application have just one weather entry per day 78 | // per location, it's created a UNIQUE constraint with REPLACE strategy 79 | " UNIQUE (" + WeatherEntry.COLUMN_DATE + ", " + 80 | WeatherEntry.COLUMN_LOC_KEY + ") ON CONFLICT REPLACE);"; 81 | 82 | sqLiteDatabase.execSQL(SQL_CREATE_LOCATION_TABLE); 83 | sqLiteDatabase.execSQL(SQL_CREATE_WEATHER_TABLE); 84 | } 85 | 86 | @Override 87 | public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { 88 | // This database is only a cache for online data, so its upgrade policy is 89 | // to simply to discard the data and start over 90 | // Note that this only fires if you change the version number for your database. 91 | // It does NOT depend on the version number for your application. 92 | // If you want to update the schema without wiping data, commenting out the next 2 lines 93 | // should be your top priority before modifying this method. 94 | sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + LocationEntry.TABLE_NAME); 95 | sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + WeatherEntry.TABLE_NAME); 96 | onCreate(sqLiteDatabase); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/gcm/MyGcmListenerService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.sunshine.app.gcm; 18 | 19 | import android.app.NotificationManager; 20 | import android.app.PendingIntent; 21 | import android.content.Context; 22 | import android.content.Intent; 23 | import android.graphics.Bitmap; 24 | import android.graphics.BitmapFactory; 25 | import android.os.Bundle; 26 | import android.support.v4.app.NotificationCompat; 27 | import android.util.Log; 28 | import android.widget.Toast; 29 | 30 | import com.example.android.sunshine.app.MainActivity; 31 | import com.example.android.sunshine.app.R; 32 | import com.google.android.gms.gcm.GcmListenerService; 33 | 34 | import org.json.JSONException; 35 | import org.json.JSONObject; 36 | 37 | public class MyGcmListenerService extends GcmListenerService { 38 | 39 | private static final String TAG = "MyGcmListenerService"; 40 | 41 | private static final String EXTRA_DATA = "data"; 42 | private static final String EXTRA_WEATHER = "weather"; 43 | private static final String EXTRA_LOCATION = "location"; 44 | 45 | public static final int NOTIFICATION_ID = 1; 46 | 47 | /** 48 | * Called when message is received. 49 | * 50 | * @param from SenderID of the sender. 51 | * @param data Data bundle containing message data as key/value pairs. 52 | * For Set of keys use data.keySet(). 53 | */ 54 | @Override 55 | public void onMessageReceived(String from, Bundle data) { 56 | // Time to unparcel the bundle! 57 | if (!data.isEmpty()) { 58 | // TODO: gcm_default sender ID comes from the API console 59 | String senderId = getString(R.string.gcm_defaultSenderId); 60 | if (senderId.length() == 0) { 61 | Toast.makeText(this, "SenderID string needs to be set", Toast.LENGTH_LONG).show(); 62 | } 63 | // Not a bad idea to check that the message is coming from your server. 64 | if ((senderId).equals(from)) { 65 | // Process message and then post a notification of the received message. 66 | try { 67 | JSONObject jsonObject = new JSONObject(data.getString(EXTRA_DATA)); 68 | String weather = jsonObject.getString(EXTRA_WEATHER); 69 | String location = jsonObject.getString(EXTRA_LOCATION); 70 | String alert = 71 | String.format(getString(R.string.gcm_weather_alert), weather, location); 72 | sendNotification(alert); 73 | } catch (JSONException e) { 74 | // JSON parsing failed, so we just let this message go, since GCM is not one 75 | // of our critical features. 76 | } 77 | } 78 | Log.i(TAG, "Received: " + data.toString()); 79 | } 80 | } 81 | 82 | /** 83 | * Put the message into a notification and post it. 84 | * This is just one simple example of what you might choose to do with a GCM message. 85 | * 86 | * @param message The alert message to be posted. 87 | */ 88 | private void sendNotification(String message) { 89 | NotificationManager mNotificationManager = 90 | (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 91 | PendingIntent contentIntent = 92 | PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0); 93 | 94 | // Notifications using both a large and a small icon (which yours should!) need the large 95 | // icon as a bitmap. So we need to create that here from the resource ID, and pass the 96 | // object along in our notification builder. Generally, you want to use the app icon as the 97 | // small icon, so that users understand what app is triggering this notification. 98 | Bitmap largeIcon = BitmapFactory.decodeResource(this.getResources(), R.drawable.art_storm); 99 | NotificationCompat.Builder mBuilder = 100 | new NotificationCompat.Builder(this) 101 | .setSmallIcon(R.drawable.art_clear) 102 | .setLargeIcon(largeIcon) 103 | .setContentTitle("Weather Alert!") 104 | .setStyle(new NotificationCompat.BigTextStyle().bigText(message)) 105 | .setContentText(message) 106 | .setPriority(NotificationCompat.PRIORITY_HIGH); 107 | mBuilder.setContentIntent(contentIntent); 108 | mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build()); 109 | } 110 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/gcm/MyInstanceIDListenerService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.android.sunshine.app.gcm; 18 | 19 | import android.content.Intent; 20 | import com.google.android.gms.iid.InstanceIDListenerService; 21 | 22 | public class MyInstanceIDListenerService extends InstanceIDListenerService { 23 | private static final String TAG = "MyInstanceIDLS"; 24 | 25 | /** 26 | * Called if InstanceID token is updated. This may occur if the security of 27 | * the previous token had been compromised. This call is initiated by the 28 | * InstanceID provider. 29 | */ 30 | @Override 31 | public void onTokenRefresh() { 32 | // Fetch updated Instance ID token. 33 | Intent intent = new Intent(this, RegistrationIntentService.class); 34 | startService(intent); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/gcm/RegistrationIntentService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app.gcm; 17 | 18 | import android.app.IntentService; 19 | import android.content.Intent; 20 | import android.content.SharedPreferences; 21 | import android.preference.PreferenceManager; 22 | import android.util.Log; 23 | import android.widget.Toast; 24 | 25 | import com.example.android.sunshine.app.MainActivity; 26 | import com.example.android.sunshine.app.R; 27 | import com.google.android.gms.gcm.GoogleCloudMessaging; 28 | import com.google.android.gms.iid.InstanceID; 29 | 30 | 31 | public class RegistrationIntentService extends IntentService { 32 | private static final String TAG = "RegIntentService"; 33 | 34 | public RegistrationIntentService() { 35 | super(TAG); 36 | } 37 | 38 | @Override 39 | protected void onHandleIntent(Intent intent) { 40 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 41 | 42 | try { 43 | // In the (unlikely) event that multiple refresh operations occur simultaneously, 44 | // ensure that they are processed sequentially. 45 | synchronized (TAG) { 46 | // Initially this call goes out to the network to retrieve the token, subsequent calls 47 | // are local. 48 | InstanceID instanceID = InstanceID.getInstance(this); 49 | 50 | // TODO: gcm_default sender ID comes from the API console 51 | String senderId = getString(R.string.gcm_defaultSenderId); 52 | if ( senderId.length() != 0 ) { 53 | String token = instanceID.getToken(senderId, 54 | GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); 55 | sendRegistrationToServer(token); 56 | } 57 | 58 | // You should store a boolean that indicates whether the generated token has been 59 | // sent to your server. If the boolean is false, send the token to your server, 60 | // otherwise your server should have already received the token. 61 | sharedPreferences.edit().putBoolean(MainActivity.SENT_TOKEN_TO_SERVER, true).apply(); 62 | } 63 | } catch (Exception e) { 64 | Log.d(TAG, "Failed to complete token refresh", e); 65 | 66 | // If an exception happens while fetching the new token or updating our registration data 67 | // on a third-party server, this ensures that we'll attempt the update at a later time. 68 | sharedPreferences.edit().putBoolean(MainActivity.SENT_TOKEN_TO_SERVER, false).apply(); 69 | } 70 | } 71 | 72 | /** 73 | * Normally, you would want to persist the registration to third-party servers. Because we do 74 | * not have a server, and are faking it with a website, you'll want to log the token instead. 75 | * That way you can see the value in logcat, and note it for future use in the website. 76 | * 77 | * @param token The new token. 78 | */ 79 | private void sendRegistrationToServer(String token) { 80 | Log.i(TAG, "GCM Registration Token: " + token); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/muzei/WeatherMuzeiSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app.muzei; 17 | 18 | import android.content.Intent; 19 | import android.database.Cursor; 20 | import android.net.Uri; 21 | 22 | import com.example.android.sunshine.app.MainActivity; 23 | import com.example.android.sunshine.app.Utility; 24 | import com.example.android.sunshine.app.data.WeatherContract; 25 | import com.example.android.sunshine.app.sync.SunshineSyncAdapter; 26 | import com.google.android.apps.muzei.api.Artwork; 27 | import com.google.android.apps.muzei.api.MuzeiArtSource; 28 | 29 | /** 30 | * Muzei source that changes your background based on the current weather conditions 31 | */ 32 | public class WeatherMuzeiSource extends MuzeiArtSource { 33 | private static final String[] FORECAST_COLUMNS = new String[]{ 34 | WeatherContract.WeatherEntry.COLUMN_WEATHER_ID, 35 | WeatherContract.WeatherEntry.COLUMN_SHORT_DESC 36 | }; 37 | // these indices must match the projection 38 | private static final int INDEX_WEATHER_ID = 0; 39 | private static final int INDEX_SHORT_DESC = 1; 40 | 41 | public WeatherMuzeiSource() { 42 | super("WeatherMuzeiSource"); 43 | } 44 | 45 | @Override 46 | protected void onHandleIntent(Intent intent) { 47 | super.onHandleIntent(intent); 48 | boolean dataUpdated = intent != null && 49 | SunshineSyncAdapter.ACTION_DATA_UPDATED.equals(intent.getAction()); 50 | if (dataUpdated && isEnabled()) { 51 | onUpdate(UPDATE_REASON_OTHER); 52 | } 53 | } 54 | 55 | @Override 56 | protected void onUpdate(int reason) { 57 | String location = Utility.getPreferredLocation(this); 58 | Uri weatherForLocationUri = WeatherContract.WeatherEntry.buildWeatherLocationWithStartDate( 59 | location, System.currentTimeMillis()); 60 | Cursor cursor = getContentResolver().query(weatherForLocationUri, FORECAST_COLUMNS, null, 61 | null, WeatherContract.WeatherEntry.COLUMN_DATE + " ASC"); 62 | if (cursor.moveToFirst()) { 63 | int weatherId = cursor.getInt(INDEX_WEATHER_ID); 64 | String desc = cursor.getString(INDEX_SHORT_DESC); 65 | 66 | String imageUrl = Utility.getImageUrlForWeatherCondition(weatherId); 67 | // Only publish a new wallpaper if we have a valid image 68 | if (imageUrl != null) { 69 | publishArtwork(new Artwork.Builder() 70 | .imageUri(Uri.parse(imageUrl)) 71 | .title(desc) 72 | .byline(location) 73 | .viewIntent(new Intent(this, MainActivity.class)) 74 | .build()); 75 | } 76 | } 77 | cursor.close(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/sync/SunshineAuthenticator.java: -------------------------------------------------------------------------------- 1 | package com.example.android.sunshine.app.sync; 2 | 3 | import android.accounts.AbstractAccountAuthenticator; 4 | import android.accounts.Account; 5 | import android.accounts.AccountAuthenticatorResponse; 6 | import android.accounts.NetworkErrorException; 7 | import android.content.Context; 8 | import android.os.Bundle; 9 | 10 | /** 11 | * Manages "Authentication" to Sunshine's backend service. The SyncAdapter framework 12 | * requires an authenticator object, so syncing to a service that doesn't need authentication 13 | * typically means creating a stub authenticator like this one. 14 | * This code is copied directly, in its entirety, from 15 | * http://developer.android.com/training/sync-adapters/creating-authenticator.html 16 | * Which is a pretty handy reference when creating your own syncadapters. Just sayin'. 17 | */ 18 | public class SunshineAuthenticator extends AbstractAccountAuthenticator { 19 | 20 | public SunshineAuthenticator(Context context) { 21 | super(context); 22 | } 23 | 24 | // No properties to edit. 25 | @Override 26 | public Bundle editProperties( 27 | AccountAuthenticatorResponse r, String s) { 28 | throw new UnsupportedOperationException(); 29 | } 30 | 31 | // Because we're not actually adding an account to the device, just return null. 32 | @Override 33 | public Bundle addAccount( 34 | AccountAuthenticatorResponse r, 35 | String s, 36 | String s2, 37 | String[] strings, 38 | Bundle bundle) throws NetworkErrorException { 39 | return null; 40 | } 41 | 42 | // Ignore attempts to confirm credentials 43 | @Override 44 | public Bundle confirmCredentials( 45 | AccountAuthenticatorResponse r, 46 | Account account, 47 | Bundle bundle) throws NetworkErrorException { 48 | return null; 49 | } 50 | 51 | // Getting an authentication token is not supported 52 | @Override 53 | public Bundle getAuthToken( 54 | AccountAuthenticatorResponse r, 55 | Account account, 56 | String s, 57 | Bundle bundle) throws NetworkErrorException { 58 | throw new UnsupportedOperationException(); 59 | } 60 | 61 | // Getting a label for the auth token is not supported 62 | @Override 63 | public String getAuthTokenLabel(String s) { 64 | throw new UnsupportedOperationException(); 65 | } 66 | 67 | // Updating user credentials is not supported 68 | @Override 69 | public Bundle updateCredentials( 70 | AccountAuthenticatorResponse r, 71 | Account account, 72 | String s, Bundle bundle) throws NetworkErrorException { 73 | throw new UnsupportedOperationException(); 74 | } 75 | 76 | // Checking features for the account is not supported 77 | @Override 78 | public Bundle hasFeatures( 79 | AccountAuthenticatorResponse r, 80 | Account account, String[] strings) throws NetworkErrorException { 81 | throw new UnsupportedOperationException(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/sync/SunshineAuthenticatorService.java: -------------------------------------------------------------------------------- 1 | package com.example.android.sunshine.app.sync; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.IBinder; 6 | 7 | /** 8 | * The service which allows the sync adapter framework to access the authenticator. 9 | */ 10 | public class SunshineAuthenticatorService extends Service { 11 | // Instance field that stores the authenticator object 12 | private SunshineAuthenticator mAuthenticator; 13 | 14 | @Override 15 | public void onCreate() { 16 | // Create a new authenticator object 17 | mAuthenticator = new SunshineAuthenticator(this); 18 | } 19 | 20 | /* 21 | * When the system binds to this Service to make the RPC call 22 | * return the authenticator's IBinder. 23 | */ 24 | @Override 25 | public IBinder onBind(Intent intent) { 26 | return mAuthenticator.getIBinder(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/sync/SunshineSyncService.java: -------------------------------------------------------------------------------- 1 | package com.example.android.sunshine.app.sync; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.IBinder; 6 | import android.util.Log; 7 | 8 | public class SunshineSyncService extends Service { 9 | private static final Object sSyncAdapterLock = new Object(); 10 | private static SunshineSyncAdapter sSunshineSyncAdapter = null; 11 | 12 | @Override 13 | public void onCreate() { 14 | Log.d("SunshineSyncService", "onCreate - SunshineSyncService"); 15 | synchronized (sSyncAdapterLock) { 16 | if (sSunshineSyncAdapter == null) { 17 | sSunshineSyncAdapter = new SunshineSyncAdapter(getApplicationContext(), true); 18 | } 19 | } 20 | } 21 | 22 | @Override 23 | public IBinder onBind(Intent intent) { 24 | return sSunshineSyncAdapter.getSyncAdapterBinder(); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/widget/DetailWidgetProvider.java: -------------------------------------------------------------------------------- 1 | package com.example.android.sunshine.app.widget; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.PendingIntent; 5 | import android.appwidget.AppWidgetManager; 6 | import android.appwidget.AppWidgetProvider; 7 | import android.content.ComponentName; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.os.Build; 11 | import android.support.annotation.NonNull; 12 | import android.support.v4.app.TaskStackBuilder; 13 | import android.widget.RemoteViews; 14 | 15 | import com.example.android.sunshine.app.DetailActivity; 16 | import com.example.android.sunshine.app.MainActivity; 17 | import com.example.android.sunshine.app.R; 18 | import com.example.android.sunshine.app.sync.SunshineSyncAdapter; 19 | 20 | /** 21 | * Provider for a scrollable weather detail widget 22 | */ 23 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 24 | public class DetailWidgetProvider extends AppWidgetProvider { 25 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 26 | // Perform this loop procedure for each App Widget that belongs to this provider 27 | for (int appWidgetId : appWidgetIds) { 28 | RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_detail); 29 | 30 | // Create an Intent to launch MainActivity 31 | Intent intent = new Intent(context, MainActivity.class); 32 | PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 33 | views.setOnClickPendingIntent(R.id.widget, pendingIntent); 34 | 35 | // Set up the collection 36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 37 | setRemoteAdapter(context, views); 38 | } else { 39 | setRemoteAdapterV11(context, views); 40 | } 41 | boolean useDetailActivity = context.getResources() 42 | .getBoolean(R.bool.use_detail_activity); 43 | Intent clickIntentTemplate = useDetailActivity 44 | ? new Intent(context, DetailActivity.class) 45 | : new Intent(context, MainActivity.class); 46 | PendingIntent clickPendingIntentTemplate = TaskStackBuilder.create(context) 47 | .addNextIntentWithParentStack(clickIntentTemplate) 48 | .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); 49 | views.setPendingIntentTemplate(R.id.widget_list, clickPendingIntentTemplate); 50 | views.setEmptyView(R.id.widget_list, R.id.widget_empty); 51 | 52 | // Tell the AppWidgetManager to perform an update on the current app widget 53 | appWidgetManager.updateAppWidget(appWidgetId, views); 54 | } 55 | } 56 | 57 | @Override 58 | public void onReceive(@NonNull Context context, @NonNull Intent intent) { 59 | super.onReceive(context, intent); 60 | if (SunshineSyncAdapter.ACTION_DATA_UPDATED.equals(intent.getAction())) { 61 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); 62 | int[] appWidgetIds = appWidgetManager.getAppWidgetIds( 63 | new ComponentName(context, getClass())); 64 | appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list); 65 | } 66 | } 67 | 68 | /** 69 | * Sets the remote adapter used to fill in the list items 70 | * 71 | * @param views RemoteViews to set the RemoteAdapter 72 | */ 73 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 74 | private void setRemoteAdapter(Context context, @NonNull final RemoteViews views) { 75 | views.setRemoteAdapter(R.id.widget_list, 76 | new Intent(context, DetailWidgetRemoteViewsService.class)); 77 | } 78 | 79 | /** 80 | * Sets the remote adapter used to fill in the list items 81 | * 82 | * @param views RemoteViews to set the RemoteAdapter 83 | */ 84 | @SuppressWarnings("deprecation") 85 | private void setRemoteAdapterV11(Context context, @NonNull final RemoteViews views) { 86 | views.setRemoteAdapter(0, R.id.widget_list, 87 | new Intent(context, DetailWidgetRemoteViewsService.class)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/android/sunshine/app/widget/TodayWidgetProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.sunshine.app.widget; 17 | 18 | import android.appwidget.AppWidgetManager; 19 | import android.appwidget.AppWidgetProvider; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.os.Bundle; 23 | import android.support.annotation.NonNull; 24 | 25 | import com.example.android.sunshine.app.sync.SunshineSyncAdapter; 26 | 27 | /** 28 | * Provider for a horizontally expandable widget showing today's weather. 29 | * 30 | * Delegates widget updating to {@link TodayWidgetIntentService} to ensure that 31 | * data retrieval is done on a background thread 32 | */ 33 | public class TodayWidgetProvider extends AppWidgetProvider { 34 | 35 | @Override 36 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 37 | context.startService(new Intent(context, TodayWidgetIntentService.class)); 38 | } 39 | 40 | @Override 41 | public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, 42 | int appWidgetId, Bundle newOptions) { 43 | context.startService(new Intent(context, TodayWidgetIntentService.class)); 44 | } 45 | 46 | @Override 47 | public void onReceive(@NonNull Context context, @NonNull Intent intent) { 48 | super.onReceive(context, intent); 49 | if (SunshineSyncAdapter.ACTION_DATA_UPDATED.equals(intent.getAction())) { 50 | context.startService(new Intent(context, TodayWidgetIntentService.class)); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi-v11/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi-v11/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/art_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/art_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_cloudy.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_current_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_current_location.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-hdpi/ic_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi-v11/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi-v11/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/art_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/art_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_cloudy.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_current_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_current_location.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-mdpi/ic_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_muzei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-nodpi/ic_muzei.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/widget_preview_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-nodpi/widget_preview_detail.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/widget_preview_today.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-nodpi/widget_preview_today.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/today_touch_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/touch_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 20 | 21 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/touch_selector_activated.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 20 | 21 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/touch_selector_base.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/touch_selector_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi-v11/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi-v11/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/art_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/art_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_cloudy.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_current_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_current_location.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xhdpi/ic_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi-v11/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi-v11/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/art_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/art_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_cloudy.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_current_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_current_location.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_fog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_light_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_light_clouds.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_light_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_light_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_rain.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_snow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_status.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_storm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/ic_storm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/mipmap/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/drawable-xxhdpi/mipmap/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/today_touch_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 20 | 21 | 23 | 24 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_selector_activated.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_selector_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 29 | 36 | 39 | 40 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/list_item_forecast_today.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 25 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout-sw600dp-port/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 24 | 25 | 34 | 35 | 46 | 47 | 50 | 56 | 57 | 67 | 68 | 78 | -------------------------------------------------------------------------------- /app/src/main/res/layout-sw600dp/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 22 | 23 | 31 | 32 | 39 | 40 | 43 | 51 | 52 | 62 | 63 | 64 | 65 | 70 | 71 | 85 | 86 | 89 | 102 | 116 | 117 | -------------------------------------------------------------------------------- /app/src/main/res/layout-sw600dp/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 26 | 27 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 16 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/detail_extras_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 29 | 30 | 37 | 38 | 47 | 48 | 55 | 56 | 65 | 66 | 67 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /app/src/main/res/layout/detail_today_grid.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | 25 | 30 | 31 | 43 | 44 | 54 | 55 | 65 | 66 | 75 | 76 | 86 | 87 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_detail.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 28 | 29 | 33 | 34 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_detail_twopane.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 27 | 28 | 31 | 32 | 37 | 38 | 39 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_detail_wide.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 27 | 28 | 33 | 34 | 37 | 38 | 44 | 45 | 46 | 47 | 56 | 57 | 60 | 61 | 72 | 73 | 81 | 82 | 94 | 95 | 96 | 104 | 105 | 116 | 117 | 125 | 126 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 22 | 23 | 27 | 28 | 34 | 35 | 42 | 50 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_main_base.xml: -------------------------------------------------------------------------------- 1 | 16 | 23 | 28 | 29 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_base_forecast_today.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 24 | 25 | 37 | 38 | 47 | 48 | 58 | 59 | 68 | 69 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_forecast.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 26 | 27 | 35 | 36 | 44 | 45 | 50 | 51 | 56 | 57 | 63 | 64 | 65 | 76 | 77 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item_forecast_today.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 25 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/pref_current_location.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 18 | 19 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 28 | 35 | 36 | 41 | 48 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_detail_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 25 | 26 | 34 | 35 | 44 | 45 | 50 | 51 | 58 | 59 | 66 | 67 | 68 | 80 | 81 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_today.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 28 | 29 | 36 | 37 | 44 | 45 | 54 | 55 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_today_large.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 28 | 29 | 36 | 37 | 50 | 51 | 64 | 65 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_today_small.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 29 | 30 | 37 | 38 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/menu/detail.xml: -------------------------------------------------------------------------------- 1 | 16 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/menu/detailfragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/menu/forecastfragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 16 | 20 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/transition-land-v21/details_window_enter_transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/transition-land-v21/details_window_return_transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/transition-v21/details_window_enter_transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/transition-v21/details_window_return_transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/values-land/refs.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 21 | 22 | @layout/fragment_detail_wide 23 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp-land/refs.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | @layout/fragment_detail_twopane 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp-port/dimens.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 80dp 19 | @dimen/abc_list_item_padding_horizontal_material 20 | @dimen/abc_list_item_padding_horizontal_material 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 0dp 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp/refs.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 21 | 22 | 23 | @layout/fragment_detail_wide 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw600dp/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw720dp-port/dimens.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 80dp 19 | @dimen/abc_list_item_padding_horizontal_material 20 | @dimen/abc_list_item_padding_horizontal_material 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values-sw720dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 64dp 20 | @dimen/abc_list_item_padding_horizontal_material 21 | @dimen/abc_action_bar_default_height_material 22 | 23 | @dimen/abc_list_item_padding_horizontal_material 24 | @dimen/abc_action_bar_default_height_material 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values-v11/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 22 | 23 | 24 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values-v14/widget_dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 0dp 18 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 23 | 24 | 27 | 28 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | @string/pref_units_label_metric 21 | @string/pref_units_label_imperial 22 | 23 | 24 | 25 | @string/pref_units_metric 26 | @string/pref_units_imperial 27 | 28 | 29 | 30 | 31 | @string/pref_art_pack_label_sunshine 32 | @string/pref_art_pack_label_cute_dogs 33 | 34 | 35 | 36 | 37 | @string/pref_art_pack_sunshine 38 | @string/pref_art_pack_cute_dogs 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | true 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | #FFFFFF 20 | #cccccc 21 | #646464 22 | #000000 23 | 24 | 25 | #03A9F4 26 | #0288D1 27 | #B3E5FC 28 | #FFD740 29 | #212121 30 | #727272 31 | 32 | 33 | #455A64 34 | #90A4AE 35 | 36 | 37 | #E0E0E0 38 | 39 | 40 | #607D8B 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 16dp 19 | 16dp 20 | 21 | 48dp 22 | 32dp 23 | 24 | 25 | 96dp 26 | 40dp 27 | 28 | 31 | 32dp 32 | 33 | 35 | 49dp 36 | 8dp 37 | 38 | 39 | @dimen/abc_list_item_padding_horizontal_material 40 | 41 | 42 | 4dp 43 | 44 | 45 | 24dp 46 | 47 | 48 | 0dp 49 | @dimen/abc_list_item_padding_horizontal_material 50 | 16dp 51 | @dimen/detail_view_padding 52 | 53 | 6dp 54 | 360dp 55 | 56 | 57 | 110dp 58 | 40dp 59 | 40dp 60 | @dimen/widget_today_default_height 61 | 220dp 62 | 63 | 250dp 64 | 180dp 65 | 220dp 66 | @dimen/widget_detail_default_height 67 | 68 | 71 | 24dp 72 | 73 | 75 | 38dp 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/res/values/refs.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | @layout/fragment_detail 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 30 | 31 | 40 | 41 | 42 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/values/widget_dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 8dp 18 | -------------------------------------------------------------------------------- /app/src/main/res/xml/authenticator.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_general.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 22 | 23 | 30 | 31 | 37 | 38 | 44 | 45 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/xml/syncadapter.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_info_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_info_today.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 27 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.0.0' 9 | classpath 'com.google.gms:google-services:1.3.0-beta1' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | jcenter() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/Advanced_Android_Development/b503732795fe5fac22b856dc53b444cb4a582d87/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 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-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------