From 24f7ff69ed5c63a10fd8277c514a377a68caec71 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Thu, 19 Feb 2026 22:01:12 +0000
Subject: [PATCH] Create monochromatic Android weather app for MV and PA
This CL creates a new Android application that displays hourly weather forecasts for Mountain View and Palo Alto, CA.
Features:
- Fetches weather data from Open-Meteo API.
- Displays hourly temperature for both locations side-by-side.
- Uses a monochromatic UI (black background, white/gray text).
- Includes Retrofit for networking and Gson for JSON parsing.
- Uses RecyclerView for efficient list display.
- Handles timezones correctly (America/Los_Angeles).
The project structure includes:
- Standard Android project layout (app module, src/main/java, src/main/res).
- Gradle build configuration.
- AndroidManifest with INTERNET permission.
Co-authored-by: hassler-google <130589279+hassler-google@users.noreply.github.com>
---
android_weather_app/.gitignore | 4 ++
android_weather_app/app/build.gradle | 36 ++++++++++
.../app/src/main/AndroidManifest.xml | 15 ++++
.../java/com/example/weatherapp/Hourly.java | 13 ++++
.../com/example/weatherapp/MainActivity.java | 70 +++++++++++++++++++
.../example/weatherapp/WeatherAdapter.java | 69 ++++++++++++++++++
.../example/weatherapp/WeatherResponse.java | 11 +++
.../example/weatherapp/WeatherService.java | 16 +++++
.../app/src/main/res/layout/activity_main.xml | 65 +++++++++++++++++
.../app/src/main/res/layout/item_weather.xml | 38 ++++++++++
.../app/src/main/res/values/colors.xml | 12 ++++
.../app/src/main/res/values/styles.xml | 10 +++
android_weather_app/build.gradle | 20 ++++++
android_weather_app/gradle.properties | 1 +
android_weather_app/settings.gradle | 1 +
15 files changed, 381 insertions(+)
create mode 100644 android_weather_app/.gitignore
create mode 100644 android_weather_app/app/build.gradle
create mode 100644 android_weather_app/app/src/main/AndroidManifest.xml
create mode 100644 android_weather_app/app/src/main/java/com/example/weatherapp/Hourly.java
create mode 100644 android_weather_app/app/src/main/java/com/example/weatherapp/MainActivity.java
create mode 100644 android_weather_app/app/src/main/java/com/example/weatherapp/WeatherAdapter.java
create mode 100644 android_weather_app/app/src/main/java/com/example/weatherapp/WeatherResponse.java
create mode 100644 android_weather_app/app/src/main/java/com/example/weatherapp/WeatherService.java
create mode 100644 android_weather_app/app/src/main/res/layout/activity_main.xml
create mode 100644 android_weather_app/app/src/main/res/layout/item_weather.xml
create mode 100644 android_weather_app/app/src/main/res/values/colors.xml
create mode 100644 android_weather_app/app/src/main/res/values/styles.xml
create mode 100644 android_weather_app/build.gradle
create mode 100644 android_weather_app/gradle.properties
create mode 100644 android_weather_app/settings.gradle
diff --git a/android_weather_app/.gitignore b/android_weather_app/.gitignore
new file mode 100644
index 0000000..a7e04a2
--- /dev/null
+++ b/android_weather_app/.gitignore
@@ -0,0 +1,4 @@
+.gradle/
+build/
+app/build/
+local.properties
diff --git a/android_weather_app/app/build.gradle b/android_weather_app/app/build.gradle
new file mode 100644
index 0000000..33740ec
--- /dev/null
+++ b/android_weather_app/app/build.gradle
@@ -0,0 +1,36 @@
+plugins {
+ id 'com.android.application'
+}
+
+android {
+ namespace 'com.example.weatherapp'
+ compileSdk 34
+
+ defaultConfig {
+ applicationId "com.example.weatherapp"
+ minSdk 24
+ targetSdk 34
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.9.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.recyclerview:recyclerview:1.3.1'
+ implementation 'com.squareup.retrofit2:retrofit:2.9.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
+}
diff --git a/android_weather_app/app/src/main/AndroidManifest.xml b/android_weather_app/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5ac0729
--- /dev/null
+++ b/android_weather_app/app/src/main/AndroidManifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android_weather_app/app/src/main/java/com/example/weatherapp/Hourly.java b/android_weather_app/app/src/main/java/com/example/weatherapp/Hourly.java
new file mode 100644
index 0000000..5039b1a
--- /dev/null
+++ b/android_weather_app/app/src/main/java/com/example/weatherapp/Hourly.java
@@ -0,0 +1,13 @@
+package com.example.weatherapp;
+
+import java.util.List;
+import com.google.gson.annotations.SerializedName;
+
+public class Hourly {
+ private List time;
+ @SerializedName("temperature_2m")
+ private List temperature2m;
+
+ public List getTime() { return time; }
+ public List getTemperature2m() { return temperature2m; }
+}
diff --git a/android_weather_app/app/src/main/java/com/example/weatherapp/MainActivity.java b/android_weather_app/app/src/main/java/com/example/weatherapp/MainActivity.java
new file mode 100644
index 0000000..c5f25c5
--- /dev/null
+++ b/android_weather_app/app/src/main/java/com/example/weatherapp/MainActivity.java
@@ -0,0 +1,70 @@
+package com.example.weatherapp;
+
+import android.os.Bundle;
+import android.util.Log;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import java.util.List;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+public class MainActivity extends AppCompatActivity {
+
+ private RecyclerView recyclerView;
+ private WeatherAdapter adapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ recyclerView = findViewById(R.id.recycler_view);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+
+ fetchWeather();
+ }
+
+ private void fetchWeather() {
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl("https://api.open-meteo.com/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+
+ WeatherService service = retrofit.create(WeatherService.class);
+
+ Call> call = service.getForecast(
+ "37.3861,37.4419",
+ "-122.0839,-122.1430",
+ "temperature_2m",
+ "America/Los_Angeles"
+ );
+
+ call.enqueue(new Callback>() {
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (response.isSuccessful() && response.body() != null && response.body().size() >= 2) {
+ WeatherResponse mvData = response.body().get(0);
+ WeatherResponse paData = response.body().get(1);
+
+ List times = mvData.getHourly().getTime();
+ List tempsMV = mvData.getHourly().getTemperature2m();
+ List tempsPA = paData.getHourly().getTemperature2m();
+
+ adapter = new WeatherAdapter(times, tempsMV, tempsPA);
+ recyclerView.setAdapter(adapter);
+ } else {
+ Log.e("WeatherApp", "Response unsuccessful or empty");
+ }
+ }
+
+ @Override
+ public void onFailure(Call> call, Throwable t) {
+ Log.e("WeatherApp", "API Call failed", t);
+ }
+ });
+ }
+}
diff --git a/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherAdapter.java b/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherAdapter.java
new file mode 100644
index 0000000..65acbe2
--- /dev/null
+++ b/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherAdapter.java
@@ -0,0 +1,69 @@
+package com.example.weatherapp;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import java.util.List;
+
+public class WeatherAdapter extends RecyclerView.Adapter {
+
+ private List times;
+ private List tempsMV;
+ private List tempsPA;
+
+ public WeatherAdapter(List times, List tempsMV, List tempsPA) {
+ this.times = times;
+ this.tempsMV = tempsMV;
+ this.tempsPA = tempsPA;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_weather, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ String time = times.get(position);
+ if (time.contains("T")) {
+ time = time.split("T")[1];
+ }
+
+ holder.tvTime.setText(time);
+
+ if (position < tempsMV.size()) {
+ holder.tvMvTemp.setText(String.format("%.1f°C", tempsMV.get(position)));
+ } else {
+ holder.tvMvTemp.setText("");
+ }
+
+ if (position < tempsPA.size()) {
+ holder.tvPaTemp.setText(String.format("%.1f°C", tempsPA.get(position)));
+ } else {
+ holder.tvPaTemp.setText("");
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return times != null ? times.size() : 0;
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ TextView tvTime;
+ TextView tvMvTemp;
+ TextView tvPaTemp;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ tvTime = itemView.findViewById(R.id.tv_time);
+ tvMvTemp = itemView.findViewById(R.id.tv_mv_temp);
+ tvPaTemp = itemView.findViewById(R.id.tv_pa_temp);
+ }
+ }
+}
diff --git a/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherResponse.java b/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherResponse.java
new file mode 100644
index 0000000..202e616
--- /dev/null
+++ b/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherResponse.java
@@ -0,0 +1,11 @@
+package com.example.weatherapp;
+
+public class WeatherResponse {
+ private double latitude;
+ private double longitude;
+ private Hourly hourly;
+
+ public double getLatitude() { return latitude; }
+ public double getLongitude() { return longitude; }
+ public Hourly getHourly() { return hourly; }
+}
diff --git a/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherService.java b/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherService.java
new file mode 100644
index 0000000..22257ac
--- /dev/null
+++ b/android_weather_app/app/src/main/java/com/example/weatherapp/WeatherService.java
@@ -0,0 +1,16 @@
+package com.example.weatherapp;
+
+import java.util.List;
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+public interface WeatherService {
+ @GET("v1/forecast")
+ Call> getForecast(
+ @Query("latitude") String latitude,
+ @Query("longitude") String longitude,
+ @Query("hourly") String hourly,
+ @Query("timezone") String timezone
+ );
+}
diff --git a/android_weather_app/app/src/main/res/layout/activity_main.xml b/android_weather_app/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..8a0d028
--- /dev/null
+++ b/android_weather_app/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android_weather_app/app/src/main/res/layout/item_weather.xml b/android_weather_app/app/src/main/res/layout/item_weather.xml
new file mode 100644
index 0000000..5b952c9
--- /dev/null
+++ b/android_weather_app/app/src/main/res/layout/item_weather.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/android_weather_app/app/src/main/res/values/colors.xml b/android_weather_app/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..fe9bad5
--- /dev/null
+++ b/android_weather_app/app/src/main/res/values/colors.xml
@@ -0,0 +1,12 @@
+
+
+ #FF000000
+ #FFFFFFFF
+ #FF333333
+ #FFCCCCCC
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+
diff --git a/android_weather_app/app/src/main/res/values/styles.xml b/android_weather_app/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..4e61d29
--- /dev/null
+++ b/android_weather_app/app/src/main/res/values/styles.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/android_weather_app/build.gradle b/android_weather_app/build.gradle
new file mode 100644
index 0000000..252492e
--- /dev/null
+++ b/android_weather_app/build.gradle
@@ -0,0 +1,20 @@
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.1.0'
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android_weather_app/gradle.properties b/android_weather_app/gradle.properties
new file mode 100644
index 0000000..5bac8ac
--- /dev/null
+++ b/android_weather_app/gradle.properties
@@ -0,0 +1 @@
+android.useAndroidX=true
diff --git a/android_weather_app/settings.gradle b/android_weather_app/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/android_weather_app/settings.gradle
@@ -0,0 +1 @@
+include ':app'