Commit 39d6f319 authored by Amit Kumar's avatar Amit Kumar

Add oreo and nougat flavours for maintaining different source for various parts

parent 7b0d96d7
......@@ -28,7 +28,17 @@ android {
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
flavorDimensions "api"
productFlavors {
apiNougat {
dimension "api"
}
apiOreo {
dimension "api"
minSdkVersion 26
}
}
// Always show the result of every unit test, even if it passes.
......@@ -47,10 +57,12 @@ dependencies {
implementation 'me.relex:circleindicator:1.2.2@aar'
implementation 'uk.co.chrisjenx:calligraphy:2.3.0'
implementation files('libs/lineage-sdk.jar')
apiNougatImplementation 'org.cyanogenmod:platform.sdk:6.0'
apiOreoImplementation files('libs/lineage-sdk.jar')
debugImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.5'
debugImplementation 'com.google.firebase:firebase-core:16.0.4'
implementation 'org.greenrobot:eventbus:3.1.1'
// Support Libs
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.indin.blisslaunchero">
<uses-permission android:name="cyanogenmod.permission.ACCESS_WEATHER_MANAGER"/>
<uses-permission android:name="cyanogenmod.permission.READ_WEATHER"/>
</manifest>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
package org.indin.blisslaunchero.features.weather;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.preference.EditTextPreference;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import org.indin.blisslaunchero.R;
import org.indin.blisslaunchero.framework.Preferences;
import java.util.HashSet;
import java.util.List;
import cyanogenmod.weather.CMWeatherManager;
import cyanogenmod.weather.WeatherLocation;
public class CustomLocationPreference extends EditTextPreference
implements CMWeatherManager.LookupCityRequestListener {
public CustomLocationPreference(Context context) {
super(context);
}
public CustomLocationPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomLocationPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private ProgressDialog mProgressDialog;
private int mCustomLocationRequestId;
private Handler mHandler;
@Override
protected void showDialog(Bundle state) {
super.showDialog(state);
mHandler = new Handler(getContext().getMainLooper());
final AlertDialog d = (AlertDialog) getDialog();
final Button okButton = d.getButton(DialogInterface.BUTTON_POSITIVE);
okButton.setOnClickListener(v -> {
CustomLocationPreference.this.onClick(d, DialogInterface.BUTTON_POSITIVE);
final String customLocationToLookUp = getEditText().getText().toString();
if (TextUtils.equals(customLocationToLookUp, "")) return;
final CMWeatherManager weatherManager = CMWeatherManager.getInstance(getContext());
mProgressDialog = new ProgressDialog(getContext());
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setMessage(getContext().getString(R.string.weather_progress_title));
mProgressDialog.setOnCancelListener(
dialog -> weatherManager.cancelRequest(mCustomLocationRequestId));
mCustomLocationRequestId = weatherManager.lookupCity(customLocationToLookUp,
CustomLocationPreference.this);
mProgressDialog.show();
});
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
String location = Preferences.getCustomWeatherLocationCity(getContext());
if (location != null) {
getEditText().setText(location);
getEditText().setSelection(location.length());
} else {
getEditText().setText("");
}
}
@Override
protected void onDialogClosed(boolean positiveResult) {
// we handle persisting the selected location below, so pretend cancel
super.onDialogClosed(false);
}
private void handleResultDisambiguation(final List<WeatherLocation> results) {
CharSequence[] items = buildItemList(results);
new AlertDialog.Builder(getContext())
.setSingleChoiceItems(items, -1, (dialog, which) -> {
applyLocation(results.get(which));
dialog.dismiss();
})
.setNegativeButton(android.R.string.cancel, null)
.setTitle(R.string.weather_select_location)
.show();
}
private CharSequence[] buildItemList(List<WeatherLocation> results) {
boolean needCountry = false, needPostal = false;
String countryId = results.get(0).getCountryId();
HashSet<String> postalIds = new HashSet<>();
for (WeatherLocation result : results) {
if (!TextUtils.equals(result.getCountryId(), countryId)) {
needCountry = true;
}
String postalId = result.getCountryId() + "##" + result.getCity();
if (postalIds.contains(postalId)) {
needPostal = true;
}
postalIds.add(postalId);
if (needPostal && needCountry) {
break;
}
}
int count = results.size();
CharSequence[] items = new CharSequence[count];
for (int i = 0; i < count; i++) {
WeatherLocation result = results.get(i);
StringBuilder builder = new StringBuilder();
if (needPostal && result.getPostalCode() != null) {
builder.append(result.getPostalCode()).append(" ");
}
builder.append(result.getCity());
if (needCountry) {
String country = result.getCountry() != null
? result.getCountry() : result.getCountryId();
builder.append(" (").append(country).append(")");
}
items[i] = builder.toString();
}
return items;
}
private void applyLocation(final WeatherLocation result) {
if (Preferences.setCustomWeatherLocation(getContext(), result)) {
String cityName = result.getCity();
String state = result.getState();
String country = result.getCountry();
setText(cityName + "," + state + "/" + country);
}
final AlertDialog d = (AlertDialog) getDialog();
d.dismiss();
}
@Override
public void onLookupCityRequestCompleted(int status, final List<WeatherLocation> locations) {
mHandler.post(() -> {
final Context context = getContext();
if (locations == null || locations.isEmpty()) {
Toast.makeText(context,
context.getString(R.string.weather_retrieve_location_dialog_title),
Toast.LENGTH_SHORT)
.show();
} else if (locations.size() > 1) {
handleResultDisambiguation(locations);
} else {
applyLocation(locations.get(0));
}
mProgressDialog.dismiss();
});
}
}
package org.indin.blisslaunchero.features.weather;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.IBinder;
import android.util.Log;
import org.indin.blisslaunchero.framework.utils.Constants;
public class DeviceStatusService extends Service {
private static final String TAG = DeviceStatusService.class.getSimpleName();
private static final boolean D = Constants.DEBUG;
private BroadcastReceiver mDeviceStatusListenerReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// Network connection has changed, make sure the weather update service knows about it
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
boolean hasConnection = !intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (D) Log.d(TAG, "Got connectivity change, has connection: " + hasConnection);
Intent i = new Intent(context, WeatherUpdateService.class);
if (hasConnection) {
context.startService(i);
} else {
context.stopService(i);
}
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
if (D) Log.d(TAG, "onDisplayOff: Cancel pending update");
WeatherUpdateService.cancelUpdates(context);
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
if (D) Log.d(TAG, "onDisplayOn: Reschedule update");
WeatherUpdateService.scheduleNextUpdate(context, false);
}
}
};
@Override
public void onCreate() {
IntentFilter deviceStatusFilter = new IntentFilter();
deviceStatusFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
deviceStatusFilter.addAction(Intent.ACTION_SCREEN_OFF);
deviceStatusFilter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mDeviceStatusListenerReceiver, deviceStatusFilter);
}
@Override
public void onDestroy() {
if (D) Log.d(TAG, "Stopping service");
unregisterReceiver(mDeviceStatusListenerReceiver);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (D) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
package org.indin.blisslaunchero.features.weather;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.CELSIUS;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.indin.blisslaunchero.R;
import org.indin.blisslaunchero.framework.Preferences;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import cyanogenmod.weather.WeatherInfo;
import cyanogenmod.weather.util.WeatherUtils;
public class ForecastBuilder {
private static final String TAG = "ForecastBuilder";
/**
* This method is used to build the small, horizontal forecasts panel
* @param context Context to be used
* @param smallPanel a horizontal linearlayout that will contain the forecasts
* @param w the Weather info object that contains the forecast data
*/
@SuppressLint("InflateParams")
public static void buildSmallPanel(Context context, LinearLayout smallPanel, WeatherInfo w) {
if (smallPanel == null) {
Log.d(TAG, "Invalid view passed");
return;
}
// Get things ready
LayoutInflater inflater
= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int color = Preferences.weatherFontColor(context);
final boolean useMetric = Preferences.useMetricUnits(context);
smallPanel.removeAllViews();
List<WeatherInfo.DayForecast> forecasts = w.getForecasts();
if (forecasts.size() <= 1) {
smallPanel.setVisibility(View.GONE);
return;
}
TimeZone MyTimezone = TimeZone.getDefault();
Calendar calendar = new GregorianCalendar(MyTimezone);
int weatherTempUnit = w.getTemperatureUnit();
int numForecasts = forecasts.size();
int itemSidePadding = context.getResources().getDimensionPixelSize(
R.dimen.forecast_item_padding_side);
// Iterate through the Forecasts
for (int count = 0; count < numForecasts; count ++) {
WeatherInfo.DayForecast d = forecasts.get(count);
// Load the views
assert inflater != null;
View forecastItem = inflater.inflate(R.layout.item_weather_forecast, null);
// The day of the week
TextView day = forecastItem.findViewById(R.id.forecast_day);
day.setText(calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT,
Locale.getDefault()));
calendar.roll(Calendar.DAY_OF_WEEK, true);
// Weather Image
ImageView image = forecastItem.findViewById(R.id.weather_image);
String iconsSet = Preferences.getWeatherIconSet(context);
final int resId = WeatherIconUtils.getWeatherIconResource(context, iconsSet,
d.getConditionCode());
if (resId != 0) {
image.setImageResource(resId);
} else {
image.setImageBitmap(WeatherIconUtils.getWeatherIconBitmap(context, iconsSet,
color, d.getConditionCode()));
}
// Temperatures
double lowTemp = d.getLow();
double highTemp = d.getHigh();
int tempUnit = weatherTempUnit;
if (weatherTempUnit == FAHRENHEIT && useMetric) {
lowTemp = cyanogenmod.weather.util.WeatherUtils.fahrenheitToCelsius(lowTemp);
highTemp = cyanogenmod.weather.util.WeatherUtils.fahrenheitToCelsius(highTemp);
tempUnit = CELSIUS;
} else if (weatherTempUnit == CELSIUS && !useMetric) {
lowTemp = cyanogenmod.weather.util.WeatherUtils.celsiusToFahrenheit(lowTemp);
highTemp = cyanogenmod.weather.util.WeatherUtils.celsiusToFahrenheit(highTemp);
tempUnit = FAHRENHEIT;
}
String dayLow = cyanogenmod.weather.util.WeatherUtils.formatTemperature(lowTemp, tempUnit);
String dayHigh = WeatherUtils.formatTemperature(highTemp, tempUnit);
TextView temps = forecastItem.findViewById(R.id.weather_temps);
temps.setText(String.format("%s\n%s", dayLow, dayHigh));
// Add the view
smallPanel.addView(forecastItem,
new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1));
// Add a divider to the right for all but the last view
if (count < numForecasts - 1) {
View divider = new View(context);
smallPanel.addView(divider, new LinearLayout.LayoutParams(
itemSidePadding, LinearLayout.LayoutParams.MATCH_PARENT));
}
}
}
}
package org.indin.blisslaunchero.features.weather;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.Log;
import org.indin.blisslaunchero.R;
import org.indin.blisslaunchero.framework.utils.Constants;
public class WeatherIconUtils {
private static final String TAG = "WeatherIconUtils";
private static boolean D = Constants.DEBUG;
public static int getWeatherIconResource(Context context, String iconSet, int conditionCode) {
if (iconSet.startsWith("ext:") || iconSet.equals(Constants.MONOCHROME)) {
return 0;
}
final Resources res = context.getResources();
final int resId = res.getIdentifier("weather_" + iconSet + "_"
+ WeatherUtils.addOffsetToConditionCodeFromWeatherContract(conditionCode), "drawable",
context.getPackageName());
if (resId != 0) {
return resId;
}
// Use the default color set unknown icon
return R.drawable.weather_color_na;
}
public static Bitmap getWeatherIconBitmap(Context context, String iconSet,
int color, int conditionCode) {
return getWeatherIconBitmap(context, iconSet, color, conditionCode, 0);
}
public static Bitmap getWeatherIconBitmap(Context context, String iconSet,
int color, int conditionCode, int density) {
boolean isMonoSet = Constants.MONOCHROME.equals(iconSet);
Resources res = null;
int resId = 0;
int fixedConditionCode = WeatherUtils.addOffsetToConditionCodeFromWeatherContract(conditionCode);
if (iconSet.startsWith("ext:")) {
String packageName = iconSet.substring(4);
try {
res = context.getPackageManager().getResourcesForApplication(packageName);
resId = res.getIdentifier("weather_" + fixedConditionCode, "drawable", packageName);
} catch (PackageManager.NameNotFoundException e) {
// fall back to colored icons
iconSet = Constants.COLOR_STD;
}
}
if (resId == 0) {
String identifier = isMonoSet
? "weather_" + fixedConditionCode : "weather_"
+ iconSet + "_" + fixedConditionCode;
res = context.getResources();
resId = res.getIdentifier(identifier, "drawable", context.getPackageName());
}
if (resId == 0) {
resId = isMonoSet ? R.drawable.weather_na : R.drawable.weather_color_na;
}
return getOverlaidBitmap(res, resId, isMonoSet ? color : 0, density);
}
public static Bitmap getOverlaidBitmap(Resources res, int resId, int color) {
return getOverlaidBitmap(res, resId, color, 0);
}
public static Bitmap getOverlaidBitmap(Resources res, int resId, int color, int density) {
Bitmap src = getBitmapFromResource(res, resId, density);
if (color == 0 || src == null) {
return src;
}
final Bitmap dest = Bitmap.createBitmap(src.getWidth(), src.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(dest);
final Paint paint = new Paint();
// Overlay the selected color and set the imageview
paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
c.drawBitmap(src, 0, 0, paint);
return dest;
}
public static Bitmap getBitmapFromResource(Resources res, int resId, int density) {
if (density == 0) {
if (D) Log.d(TAG, "Decoding resource id = " + resId + " for default density");
return BitmapFactory.decodeResource(res, resId);
}
if (D) Log.d(TAG, "Decoding resource id = " + resId + " for density = " + density);
Drawable d = res.getDrawableForDensity(resId, density);
if (d instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) d;
return bd.getBitmap();
}
Bitmap result = Bitmap.createBitmap(d.getIntrinsicWidth(),
d.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
d.setBounds(0, 0, result.getWidth(), result.getHeight());
d.draw(canvas);
canvas.setBitmap(null);
return result;
}
public static int getNextHigherDensity(Context context) {
Resources res = context.getResources();
int density = res.getDisplayMetrics().densityDpi;
if (density == DisplayMetrics.DENSITY_LOW) {
return DisplayMetrics.DENSITY_MEDIUM;
} else if (density == DisplayMetrics.DENSITY_MEDIUM) {
return DisplayMetrics.DENSITY_HIGH;
} else if (density == DisplayMetrics.DENSITY_HIGH) {
return DisplayMetrics.DENSITY_XHIGH;
} else if (density == DisplayMetrics.DENSITY_XHIGH) {
return DisplayMetrics.DENSITY_XXHIGH;
} else if (density == DisplayMetrics.DENSITY_XXHIGH) {
return DisplayMetrics.DENSITY_XXXHIGH;
}
// fallback: use current density
return density;
}
}
package org.indin.blisslaunchero.features.weather;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import org.indin.blisslaunchero.framework.Preferences;
import org.indin.blisslaunchero.framework.utils.Constants;
import cyanogenmod.weather.CMWeatherManager;
public class WeatherSourceListenerService extends Service
implements CMWeatherManager.WeatherServiceProviderChangeListener {
private static final String TAG = WeatherSourceListenerService.class.getSimpleName();
private static final boolean D = Constants.DEBUG;
private Context mContext;
private volatile boolean mRegistered;
@Override
public void onWeatherServiceProviderChanged(String providerLabel) {
if (D) Log.d(TAG, "Weather Source changed " + providerLabel);
Preferences.setWeatherSource(mContext, providerLabel);
Preferences.setCachedWeatherInfo(mContext, 0, null);
//The data contained in WeatherLocation is tightly coupled to the weather provider
//that generated that data, so we need to clear the cached weather location and let the new
//weather provider regenerate the data if the user decides to use custom location again
Preferences.setCustomWeatherLocationCity(mContext, null);
Preferences.setCustomWeatherLocation(mContext, null);
Preferences.setUseCustomWeatherLocation(mContext, false);
if (providerLabel != null) {
mContext.startService(new Intent(mContext, WeatherUpdateService.class)
.putExtra(WeatherUpdateService.ACTION_FORCE_UPDATE, true));
}
}
@Override
public void onCreate() {
mContext = getApplicationContext();
final CMWeatherManager weatherManager
= CMWeatherManager.getInstance(mContext);
weatherManager.registerWeatherServiceProviderChangeListener(this);
mRegistered = true;
if (D) Log.d(TAG, "Listener registered");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onDestroy() {
if (mRegistered) {
final CMWeatherManager weatherManager = CMWeatherManager.getInstance(mContext);
weatherManager.unregisterWeatherServiceProviderChangeListener(this);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
package org.indin.blisslaunchero.features.weather;
import android.content.Context;
import android.content.res.Resources;
import org.indin.blisslaunchero.R;
import java.text.DecimalFormat;
import cyanogenmod.app.CMContextConstants;
import cyanogenmod.providers.WeatherContract;
public final class WeatherUtils {
private static final DecimalFormat sNoDigitsFormat = new DecimalFormat("0");
// In doubt? See https://en.wikipedia.org/wiki/Points_of_the_compass
private static final double DIRECTION_NORTH = 23d;
private static final double DIRECTION_NORTH_EAST = 68d;
private static final double DIRECTION_EAST = 113d;
private static final double DIRECTION_SOUTH_EAST = 158d;
private static final double DIRECTION_SOUTH = 203d;
private static final double DIRECTION_SOUTH_WEST = 248d;
private static final double DIRECTION_WEST = 293d;
private static final double DIRECTION_NORTH_WEST = 338d;
private static boolean weatherServiceFeatureCached;
private static boolean weatherServiceAvailable;
/**
* Returns a localized string of the wind direction
* @param context Application context to access resources
* @param windDirection The wind direction in degrees
* @return The wind direction in string format
*/