aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdnan Begovic <adnan@cyngn.com>2016-04-18 14:22:36 -0700
committerAdnan Begovic <adnan@cyngn.com>2016-04-20 14:12:38 -0700
commita6f49ab9fdd72ec75a9f43efbe66537d33486dbd (patch)
treee658188ca0b6f58077e3f39b866908d3cce89667
parent2a77ad45d9e66427f5899da32a611586e191a0c2 (diff)
downloadandroid_packages_apps_WundergroundWeatherProvider-a6f49ab9fdd72ec75a9f43efbe66537d33486dbd.tar.gz
android_packages_apps_WundergroundWeatherProvider-a6f49ab9fdd72ec75a9f43efbe66537d33486dbd.tar.bz2
android_packages_apps_WundergroundWeatherProvider-a6f49ab9fdd72ec75a9f43efbe66537d33486dbd.zip
WundergroundCM: Add api key verification mechanism.
Change-Id: I9c5d077356de8532c7efd002042f1f7ab1aa021e
-rw-r--r--app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/ApiKeyInterceptor.java54
-rw-r--r--app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WUBasePreferenceActivity.java156
-rw-r--r--app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WundergroundModule.java2
-rw-r--r--app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/wunderground/WundergroundServiceManager.java29
-rw-r--r--app/src/main/res/values/colors.xml17
-rw-r--r--app/src/main/res/values/strings.xml2
6 files changed, 247 insertions, 13 deletions
diff --git a/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/ApiKeyInterceptor.java b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/ApiKeyInterceptor.java
new file mode 100644
index 0000000..034786e
--- /dev/null
+++ b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/ApiKeyInterceptor.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.cyanogenmod.wundergroundcmweatherprovider;
+
+import java.io.IOException;
+
+import okhttp3.HttpUrl;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * Inspired by https://gist.github.com/swankjesse/8571a8207a5815cca1fb
+ */
+public class ApiKeyInterceptor implements Interceptor {
+
+ /** http://api.wunderground.com/api/<API KEY>//<features...>/q/<location>.json **/
+ private static final int API_KEY_PATH_SEGMENT = 1;
+
+ private volatile String mApiKey;
+
+ public void setApiKey(String apiKey) {
+ this.mApiKey = apiKey;
+ }
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Request request = chain.request();
+ String apiKey = mApiKey;
+ if (apiKey != null) {
+ HttpUrl newUrl = request.url().newBuilder()
+ .setPathSegment(API_KEY_PATH_SEGMENT, apiKey)
+ .build();
+ request = request.newBuilder()
+ .url(newUrl)
+ .build();
+ }
+ return chain.proceed(request);
+ }
+}
diff --git a/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WUBasePreferenceActivity.java b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WUBasePreferenceActivity.java
index 1d0dd20..53e716c 100644
--- a/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WUBasePreferenceActivity.java
+++ b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WUBasePreferenceActivity.java
@@ -20,16 +20,37 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Message;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.text.Editable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.ForegroundColorSpan;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
-public class WUBasePreferenceActivity extends PreferenceActivity implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
+import org.cyanogenmod.wundergroundcmweatherprovider.wunderground.Feature;
+import org.cyanogenmod.wundergroundcmweatherprovider.wunderground.WundergroundServiceManager;
+import org.cyanogenmod.wundergroundcmweatherprovider.wunderground.responses.CurrentObservationResponse;
+import org.cyanogenmod.wundergroundcmweatherprovider.wunderground.responses.WundergroundReponse;
+
+import javax.inject.Inject;
+
+import cyanogenmod.weather.WeatherLocation;
+import retrofit2.Call;
+import retrofit2.Response;
+
+public class WUBasePreferenceActivity extends PreferenceActivity implements
+ Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
+
+ private static final String TAG = WUBasePreferenceActivity.class.getSimpleName();
private static final String CREATE_ACCOUNT_KEY = "create_account";
private static final String API_KEY_KEY = "api_key";
@@ -37,9 +58,15 @@ public class WUBasePreferenceActivity extends PreferenceActivity implements Pref
private static final String WU_CREATE_ACCOUNT_URL =
"https://www.wunderground.com/weather/api/d/login.html";
+ private static final int VERIFY_API_KEY = 0;
+ private static final int UPDATE_SUMMARIES = 1;
+
private Preference mCreateAccountPreference;
private EditTextPreference mApiKeyPreference;
+ @Inject
+ WundergroundServiceManager mWundergroundServiceManager;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -55,6 +82,10 @@ public class WUBasePreferenceActivity extends PreferenceActivity implements Pref
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
+
+ if (getSharedPreferences().contains(WundergroundModule.API_KEY_VERIFIED)) {
+ updateSummaries();
+ }
}
@Override
@@ -72,11 +103,19 @@ public class WUBasePreferenceActivity extends PreferenceActivity implements Pref
switch (preference.getKey()) {
case API_KEY_KEY:
Editable editText = mApiKeyPreference.getEditText().getText();
- if (editText != null) {
- String text = editText.toString();
- SharedPreferences sharedPreferences = getSharedPreferences(
- WundergroundModule.SHARED_PREFS_KEY, Context.MODE_PRIVATE);
- sharedPreferences.edit().putString(WundergroundModule.API_KEY, text).commit();
+ String text = editText.toString();
+
+ if (!TextUtils.isEmpty(text)) {
+ SharedPreferences.Editor editor = getSharedPreferences().edit();
+ editor.putString(WundergroundModule.API_KEY, text);
+ editor.commit();
+
+ mWundergroundServiceManager.updateApiKey(text);
+
+ Message verifyApiKeyMessage = mHandler.obtainMessage();
+ verifyApiKeyMessage.sendToTarget();
+ } else {
+ passedVerification(false);
}
return true;
}
@@ -99,4 +138,109 @@ public class WUBasePreferenceActivity extends PreferenceActivity implements Pref
}
return false;
}
+
+ private final NonLeakyMessageHandler mHandler = new NonLeakyMessageHandler(this);
+
+ private static class NonLeakyMessageHandler extends
+ WeakReferenceHandler<WUBasePreferenceActivity> {
+
+ public NonLeakyMessageHandler(WUBasePreferenceActivity reference) {
+ super(reference);
+ }
+
+ @Override
+ protected void handleMessage(WUBasePreferenceActivity reference, Message msg) {
+ switch (msg.what) {
+ case VERIFY_API_KEY:
+ Log.d(TAG, "Verifying api key...");
+ reference.verifyReceivedWeatherInfoByPostalCode();
+ break;
+ case UPDATE_SUMMARIES:
+ reference.updateSummaries();
+ break;
+ }
+ }
+ }
+
+ private SharedPreferences getSharedPreferences() {
+ return getSharedPreferences(WundergroundModule.SHARED_PREFS_KEY, Context.MODE_PRIVATE);
+ }
+
+ private void updateSummaries() {
+ final SharedPreferences sharedPreferences = getSharedPreferences();
+ final Resources resources = getResources();
+ boolean verified = sharedPreferences.getBoolean(WundergroundModule.API_KEY_VERIFIED, false);
+
+ Log.d(TAG, "Updating summaries, verified " + verified);
+
+ ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(verified ?
+ resources.getColor(R.color.green) :
+ resources.getColor(R.color.red));
+
+ Spannable summary = new SpannableString(verified ?
+ getString(R.string.authentication_preference_api_key_verified) :
+ getString(R.string.authentication_preference_api_key_not_verified));
+
+ summary.setSpan(foregroundColorSpan, 0, summary.length(), 0);
+ mApiKeyPreference.setSummary(summary);
+ }
+
+ private void verifyReceivedWeatherInfoByPostalCode() {
+ WeatherLocation weatherLocation = new WeatherLocation.Builder("Seattle")
+ .setPostalCode("98121")
+ .setCountry("US")
+ .setState("WA")
+ .build();
+
+ Call<WundergroundReponse> wundergroundCall =
+ mWundergroundServiceManager.query(weatherLocation.getPostalCode(),
+ Feature.conditions, Feature.forecast);
+
+ Log.d(TAG, "Enqueue api request...");
+ wundergroundCall.enqueue(new retrofit2.Callback<WundergroundReponse>() {
+ @Override
+ public void onResponse(Call<WundergroundReponse> call,
+ Response<WundergroundReponse> response) {
+ Log.d(TAG, "Response " + response.toString());
+ if (response.isSuccessful()) {
+ WundergroundReponse wundergroundReponse = response.body();
+
+ if (wundergroundReponse == null) {
+ passedVerification(false);
+ return;
+ }
+
+ CurrentObservationResponse currentObservationResponse =
+ wundergroundReponse.getCurrentObservation();
+
+ if (currentObservationResponse == null) {
+ passedVerification(false);
+ } else {
+ passedVerification(true);
+ }
+ } else {
+ passedVerification(false);
+ }
+ }
+
+ @Override
+ public void onFailure(Call<WundergroundReponse> call, Throwable t) {
+ Log.d(TAG, "Response " + t.toString());
+ passedVerification(false);
+ }
+ });
+ }
+
+ private void passedVerification(boolean passed) {
+ Log.d(TAG, "Passed verification" + passed);
+ final SharedPreferences.Editor editor = getSharedPreferences().edit();
+ editor.putBoolean(WundergroundModule.API_KEY_VERIFIED, passed);
+ editor.apply();
+ update();
+ }
+
+ private void update() {
+ Message message = mHandler.obtainMessage(UPDATE_SUMMARIES);
+ message.sendToTarget();
+ }
}
diff --git a/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WundergroundModule.java b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WundergroundModule.java
index 553e03c..aa5951b 100644
--- a/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WundergroundModule.java
+++ b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/WundergroundModule.java
@@ -37,6 +37,8 @@ public class WundergroundModule {
public static final String SHARED_PREFS_KEY = "WU_SHARED_PREFS";
public static final String API_KEY = "API_KEY";
+ public static final String API_KEY_VERIFIED = "API_KEY_VERIFIED";
+
private WundergroundCMApplication mWeatherviewApplication;
public WundergroundModule(WundergroundCMApplication weatherviewApplication) {
diff --git a/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/wunderground/WundergroundServiceManager.java b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/wunderground/WundergroundServiceManager.java
index ffcde0e..6649330 100644
--- a/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/wunderground/WundergroundServiceManager.java
+++ b/app/src/main/java/org/cyanogenmod/wundergroundcmweatherprovider/wunderground/WundergroundServiceManager.java
@@ -20,6 +20,7 @@ import android.util.Log;
import com.google.common.base.Joiner;
+import org.cyanogenmod.wundergroundcmweatherprovider.ApiKeyInterceptor;
import org.cyanogenmod.wundergroundcmweatherprovider.wunderground.responses.WundergroundReponse;
import okhttp3.OkHttpClient;
@@ -29,10 +30,14 @@ import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class WundergroundServiceManager {
- private final static String TAG = WundergroundServiceManager.class.getSimpleName();
+ private final static String TAG = "WundergroundManager";
+ private final static boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
+
private final WundergroundServiceInterface mWundergroundServiceInterface;
+ private final ApiKeyInterceptor mApiKeyInterceptor;
public WundergroundServiceManager(String apiKey) {
+ mApiKeyInterceptor = new ApiKeyInterceptor();
Retrofit baseAdapter = buildRestAdapter(apiKey);
mWundergroundServiceInterface = baseAdapter.create(WundergroundServiceInterface.class);
}
@@ -58,19 +63,29 @@ public class WundergroundServiceManager {
return mWundergroundServiceInterface.lookupCity(city);
}
+ public void updateApiKey(String apiKey) {
+ mApiKeyInterceptor.setApiKey(apiKey);
+ }
+
private String coerceVarArgFeaturesToDelimitedString(FeatureParam... featureParams) {
return Joiner.on('/').join(featureParams);
}
private Retrofit buildRestAdapter(String apiKey) {
- //TODO: Wrap this in debug flag
- //HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
- //interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- //OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
+ final OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
+ if (DEBUG) {
+ final HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
+ loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ builder.addInterceptor(loggingInterceptor);
+ }
+ mApiKeyInterceptor.setApiKey(apiKey);
+ builder.addInterceptor(mApiKeyInterceptor);
+ final OkHttpClient client = builder.build();
+ final String baseUrl = "http://api.wunderground.com/api/" + apiKey + "/";
return new Retrofit.Builder()
- .baseUrl("http://api.wunderground.com/api/" + apiKey + "/")
- //.client(client)
+ .baseUrl(baseUrl)
+ .client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..88b1caa
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The CyanogenMod Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <item name="red" type="color">#FFFF4444</item>
+ <item name="green" type="color">#FF99CC00</item>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ba0220c..b5c42a1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -17,6 +17,8 @@
<string name="authentication_preference_category_title">Authentication</string>
<string name="authentication_preference_api_key">API key</string>
<string name="authentication_preference_api_key_summary">API key to be utilized for Weather Underground authentication</string>
+ <string name="authentication_preference_api_key_verified">Authenticated</string>
+ <string name="authentication_preference_api_key_not_verified">Unable to authenticate</string>
<string name="authentication_preference_account_create">Create account</string>
<string name="authentication_preference_account_create_summary">Create an account to get an API key for weather data usage</string>
<string name="about_preference_category_title">About</string>