Last active
May 31, 2023 02:45
-
-
Save pknujsp/25c2c11d6dae6138cd0bbd1b7d3f768d to your computer and use it in GitHub Desktop.
Android app widget example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lifedawn.bestweather.widget.creator; | |
import android.app.PendingIntent; | |
import android.appwidget.AppWidgetManager; | |
import android.appwidget.AppWidgetProviderInfo; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.content.res.Configuration; | |
import android.graphics.Bitmap; | |
import android.os.Bundle; | |
import android.util.ArrayMap; | |
import android.util.TypedValue; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.RelativeLayout; | |
import android.widget.RemoteViews; | |
import android.widget.TextView; | |
import androidx.annotation.Nullable; | |
import androidx.preference.PreferenceManager; | |
import com.google.gson.JsonObject; | |
import com.lifedawn.bestweather.R; | |
import com.lifedawn.bestweather.commons.enums.IntentRequestCodes; | |
import com.lifedawn.bestweather.commons.enums.LocationType; | |
import com.lifedawn.bestweather.commons.enums.WeatherDataType; | |
import com.lifedawn.bestweather.commons.enums.ValueUnits; | |
import com.lifedawn.bestweather.commons.enums.WeatherProviderType; | |
import com.lifedawn.bestweather.forremoteviews.RemoteViewsUtil; | |
import com.lifedawn.bestweather.main.MyApplication; | |
import com.lifedawn.bestweather.retrofit.client.RetrofitClient; | |
import com.lifedawn.bestweather.retrofit.util.WeatherRestApiDownloader; | |
import com.lifedawn.bestweather.room.callback.DbQueryCallback; | |
import com.lifedawn.bestweather.room.dto.WidgetDto; | |
import com.lifedawn.bestweather.room.repository.WidgetRepository; | |
import com.lifedawn.bestweather.theme.AppTheme; | |
import com.lifedawn.bestweather.widget.DialogActivity; | |
import com.lifedawn.bestweather.widget.OnDrawBitmapCallback; | |
import com.lifedawn.bestweather.widget.widgetprovider.EighthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.EleventhWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FifthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FirstWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FourthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.NinthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SecondWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SeventhWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SixthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.TenthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.ThirdWidgetProvider; | |
import java.time.ZoneId; | |
import java.time.ZoneOffset; | |
import java.time.ZonedDateTime; | |
import java.time.format.DateTimeFormatter; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.concurrent.ConcurrentHashMap; | |
import java.util.concurrent.atomic.AtomicInteger; | |
import static android.view.View.MeasureSpec.EXACTLY; | |
public abstract class AbstractWidgetCreator { | |
protected final DateTimeFormatter refreshDateTimeFormatter = DateTimeFormatter.ofPattern("M.d E a h:mm"); | |
protected final int appWidgetId; | |
protected final ValueUnits tempUnit; | |
protected final ValueUnits clockUnit; | |
protected final String tempDegree; | |
protected ZoneId zoneId; | |
protected Context context; | |
protected WidgetUpdateCallback widgetUpdateCallback; | |
protected WidgetDto widgetDto; | |
protected WidgetRepository widgetRepository; | |
protected AppWidgetManager appWidgetManager; | |
protected RemoteViewsCallback remoteViewsCallback; | |
public AbstractWidgetCreator setRemoteViewsCallback(RemoteViewsCallback remoteViewsCallback) { | |
this.remoteViewsCallback = remoteViewsCallback; | |
return this; | |
} | |
public AbstractWidgetCreator setWidgetDto(WidgetDto widgetDto) { | |
this.widgetDto = widgetDto; | |
return this; | |
} | |
public static AbstractWidgetCreator getInstance(AppWidgetManager appWidgetManager, Context context, int appWidgetId) { | |
AppWidgetProviderInfo appWidgetProviderInfo = appWidgetManager.getAppWidgetInfo(appWidgetId); | |
final String providerClassName = appWidgetProviderInfo.provider.getClassName(); | |
if (providerClassName.equals(FirstWidgetProvider.class.getName())) { | |
return new FirstWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(SecondWidgetProvider.class.getName())) { | |
return new SecondWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(ThirdWidgetProvider.class.getName())) { | |
return new ThirdWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(FourthWidgetProvider.class.getName())) { | |
return new FourthWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(FifthWidgetProvider.class.getName())) { | |
return new FifthWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(SixthWidgetProvider.class.getName())) { | |
return new SixthWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(SeventhWidgetProvider.class.getName())) { | |
return new SeventhWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(EighthWidgetProvider.class.getName())) { | |
return new EighthWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(NinthWidgetProvider.class.getName())) { | |
return new NinthWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(TenthWidgetProvider.class.getName())) { | |
return new TenthWidgetCreator(context, null, appWidgetId); | |
} else if (providerClassName.equals(EleventhWidgetProvider.class.getName())) { | |
return new EleventhWidgetCreator(context, null, appWidgetId); | |
} else { | |
return null; | |
} | |
} | |
public abstract RemoteViews createTempViews(Integer parentWidth, Integer parentHeight); | |
public Context getContext() { | |
return context; | |
} | |
public AbstractWidgetCreator(Context context, WidgetUpdateCallback widgetUpdateCallback, int appWidgetId) { | |
this.context = context; | |
this.widgetUpdateCallback = widgetUpdateCallback; | |
this.appWidgetId = appWidgetId; | |
tempUnit = MyApplication.VALUE_UNIT_OBJ.getTempUnit(); | |
clockUnit = MyApplication.VALUE_UNIT_OBJ.getClockUnit(); | |
tempDegree = MyApplication.VALUE_UNIT_OBJ.getTempUnitText(); | |
widgetRepository = WidgetRepository.getINSTANCE(); | |
appWidgetManager = AppWidgetManager.getInstance(context); | |
} | |
public void setRefreshPendingIntent(RemoteViews remoteViews) { | |
remoteViews.setOnClickPendingIntent(R.id.refreshBtn, getRefreshPendingIntent()); | |
} | |
public PendingIntent getRefreshPendingIntent() { | |
Intent refreshIntent = new Intent(context, FirstWidgetProvider.class); | |
refreshIntent.setAction(context.getString(R.string.com_lifedawn_bestweather_action_REFRESH)); | |
return PendingIntent.getBroadcast(context, IntentRequestCodes.WIDGET_MANUALLY_REFRESH.requestCode, refreshIntent, | |
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); | |
} | |
public WidgetDto loadDefaultSettings() { | |
widgetDto = new WidgetDto(); | |
widgetDto.setAppWidgetId(appWidgetId); | |
widgetDto.setMultipleWeatherDataSource(false); | |
widgetDto.setWidgetProviderClassName(widgetProviderClass().getName()); | |
widgetDto.setBackgroundAlpha(100); | |
widgetDto.setDisplayClock(true); | |
widgetDto.setDisplayLocalClock(false); | |
widgetDto.setLocationType(LocationType.CurrentLocation); | |
widgetDto.addWeatherProviderType(PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean(context.getString(R.string.pref_key_met), true) ? | |
WeatherProviderType.MET_NORWAY : WeatherProviderType.OWM_ONECALL); | |
widgetDto.setTextSizeAmount(0); | |
widgetDto.setTopPriorityKma(true); | |
if (getRequestWeatherDataTypeSet().contains(WeatherDataType.airQuality)) { | |
widgetDto.getWeatherProviderTypeSet().add(WeatherProviderType.AQICN); | |
} | |
return widgetDto; | |
} | |
public void loadSavedSettings(@Nullable DbQueryCallback<WidgetDto> callback) { | |
widgetRepository.get(appWidgetId, new DbQueryCallback<WidgetDto>() { | |
@Override | |
public void onResultSuccessful(WidgetDto result) { | |
widgetDto = result; | |
if (callback != null) { | |
callback.onResultSuccessful(widgetDto); | |
} | |
} | |
@Override | |
public void onResultNoData() { | |
} | |
}); | |
} | |
public void saveSettings(WidgetDto widgetDto, @Nullable DbQueryCallback<WidgetDto> callback) { | |
widgetRepository.add(widgetDto, new DbQueryCallback<WidgetDto>() { | |
@Override | |
public void onResultSuccessful(WidgetDto result) { | |
if (callback != null) { | |
callback.onResultSuccessful(result); | |
} | |
} | |
@Override | |
public void onResultNoData() { | |
} | |
}); | |
} | |
public void updateSettings(WidgetDto widgetDto, @Nullable DbQueryCallback<WidgetDto> callback) { | |
widgetRepository.update(widgetDto, new DbQueryCallback<WidgetDto>() { | |
@Override | |
public void onResultSuccessful(WidgetDto result) { | |
if (callback != null) { | |
callback.onResultSuccessful(result); | |
} | |
} | |
@Override | |
public void onResultNoData() { | |
} | |
}); | |
} | |
protected void setBackgroundAlpha(RemoteViews remoteViews, int backgroundAlpha) { | |
float opacity = widgetDto.getBackgroundAlpha() / 100f; | |
int newBackgroundColor = (int) (opacity * 0xFF) << 24 | AppTheme.getColor(context, R.color.widgetBackgroundColor); | |
remoteViews.setInt(R.id.root_layout, "setBackgroundColor", newBackgroundColor); | |
} | |
public PendingIntent getOnClickedPendingIntent() { | |
Intent intent = new Intent(context, DialogActivity.class); | |
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |
Bundle bundle = new Bundle(); | |
bundle.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); | |
intent.putExtras(bundle); | |
return PendingIntent.getActivity(context, IntentRequestCodes.CLICK_WIDGET.requestCode, intent, | |
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); | |
} | |
protected int getWidgetSizeInDp(AppWidgetManager appWidgetManager, String key) { | |
return appWidgetManager.getAppWidgetOptions(appWidgetId).getInt(key, 0); | |
} | |
/** | |
* @param | |
* @return {widgetWidthPx, widgetHeightPx} 반환 | |
*/ | |
public int[] getWidgetExactSizeInPx(AppWidgetManager appWidgetManager) { | |
int widgetWidth = 0; | |
int widgetHeight = 0; | |
int portrait = context.getResources().getConfiguration().orientation; | |
if (portrait == Configuration.ORIENTATION_PORTRAIT) { | |
widgetWidth = getWidgetSizeInDp(appWidgetManager, AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH); | |
widgetHeight = getWidgetSizeInDp(appWidgetManager, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT); | |
} else { | |
widgetWidth = getWidgetSizeInDp(appWidgetManager, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH); | |
widgetHeight = getWidgetSizeInDp(appWidgetManager, AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT); | |
} | |
float density = context.getResources().getDisplayMetrics().density; | |
float widgetWidthPx = widgetWidth * density; | |
float widgetHeightPx = widgetHeight * density; | |
return new int[]{(int) widgetWidthPx, (int) widgetHeightPx}; | |
} | |
public void makeResponseTextToJson(WeatherRestApiDownloader weatherRestApiDownloader, Set<WeatherDataType> weatherDataTypeSet, | |
Set<WeatherProviderType> weatherProviderTypeSet, WidgetDto widgetDto, ZoneOffset zoneOffset) { | |
//json형태로 저장 | |
/* | |
examples : | |
{ | |
"KMA":{ | |
"ULTRA_SRT_NCST": ~~json text~~, | |
"ULTRA_SRT_FCST": ~~json text~~ | |
}, | |
"OPEN_WEATHER_MAP":{ | |
"OWM_ONE_CALL": ~~json text~~ | |
}, | |
"zoneOffset": "09:00" | |
} | |
*/ | |
Map<WeatherProviderType, ArrayMap<RetrofitClient.ServiceType, WeatherRestApiDownloader.ResponseResult>> arrayMap = | |
weatherRestApiDownloader.getResponseMap(); | |
final JsonObject rootJsonObject = new JsonObject(); | |
String text = null; | |
//owm이면 onecall이므로 한번만 수행 | |
for (WeatherProviderType weatherProviderType : weatherProviderTypeSet) { | |
ArrayMap<RetrofitClient.ServiceType, WeatherRestApiDownloader.ResponseResult> requestWeatherSourceArr = | |
arrayMap.get(weatherProviderType); | |
if (weatherProviderType == WeatherProviderType.OWM_ONECALL) { | |
JsonObject owmJsonObject = new JsonObject(); | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.OWM_ONE_CALL).getResponseText(); | |
owmJsonObject.addProperty(RetrofitClient.ServiceType.OWM_ONE_CALL.name(), text); | |
rootJsonObject.add(weatherProviderType.name(), owmJsonObject); | |
} else if (weatherProviderType == WeatherProviderType.MET_NORWAY) { | |
JsonObject metNorwayJsonObject = new JsonObject(); | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.MET_NORWAY_LOCATION_FORECAST).getResponseText(); | |
metNorwayJsonObject.addProperty(RetrofitClient.ServiceType.MET_NORWAY_LOCATION_FORECAST.name(), text); | |
rootJsonObject.add(weatherProviderType.name(), metNorwayJsonObject); | |
} else if (weatherProviderType == WeatherProviderType.OWM_INDIVIDUAL) { | |
JsonObject owmIndividualJsonObject = new JsonObject(); | |
if (weatherDataTypeSet.contains(WeatherDataType.currentConditions)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.OWM_CURRENT_CONDITIONS).getResponseText(); | |
owmIndividualJsonObject.addProperty(RetrofitClient.ServiceType.OWM_CURRENT_CONDITIONS.name(), text); | |
} | |
if (weatherDataTypeSet.contains(WeatherDataType.hourlyForecast)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.OWM_HOURLY_FORECAST).getResponseText(); | |
owmIndividualJsonObject.addProperty(RetrofitClient.ServiceType.OWM_HOURLY_FORECAST.name(), text); | |
} | |
if (weatherDataTypeSet.contains(WeatherDataType.dailyForecast)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.OWM_DAILY_FORECAST).getResponseText(); | |
owmIndividualJsonObject.addProperty(RetrofitClient.ServiceType.OWM_DAILY_FORECAST.name(), text); | |
} | |
rootJsonObject.add(weatherProviderType.name(), owmIndividualJsonObject); | |
} else if (weatherProviderType == WeatherProviderType.KMA_API) { | |
JsonObject kmaJsonObject = new JsonObject(); | |
if (weatherDataTypeSet.contains(WeatherDataType.currentConditions)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_ULTRA_SRT_NCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_ULTRA_SRT_NCST.name(), text); | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST.name(), text); | |
} | |
if (weatherDataTypeSet.contains(WeatherDataType.hourlyForecast)) { | |
if (!kmaJsonObject.has(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST.name())) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST.name(), text); | |
} | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_VILAGE_FCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_VILAGE_FCST.name(), text); | |
} | |
if (weatherDataTypeSet.contains(WeatherDataType.dailyForecast)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_MID_TA_FCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_MID_TA_FCST.name(), text); | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_MID_LAND_FCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_MID_LAND_FCST.name(), text); | |
if (!kmaJsonObject.has(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST.name())) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_ULTRA_SRT_FCST.name(), text); | |
} | |
if (!kmaJsonObject.has(RetrofitClient.ServiceType.KMA_VILAGE_FCST.name())) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_VILAGE_FCST).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_VILAGE_FCST.name(), text); | |
} | |
long tmFc = Long.parseLong(weatherRestApiDownloader.get("tmFc")); | |
kmaJsonObject.addProperty("tmFc", tmFc); | |
} | |
rootJsonObject.add(weatherProviderType.name(), kmaJsonObject); | |
} else if (weatherProviderType == WeatherProviderType.KMA_WEB) { | |
JsonObject kmaJsonObject = new JsonObject(); | |
if (weatherDataTypeSet.contains(WeatherDataType.currentConditions)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_WEB_CURRENT_CONDITIONS).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_WEB_CURRENT_CONDITIONS.name(), text); | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_WEB_FORECASTS).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_WEB_FORECASTS.name(), text); | |
} | |
if (!kmaJsonObject.has(RetrofitClient.ServiceType.KMA_WEB_FORECASTS.name())) { | |
if (weatherDataTypeSet.contains(WeatherDataType.hourlyForecast) || weatherDataTypeSet.contains(WeatherDataType.dailyForecast)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.KMA_WEB_FORECASTS).getResponseText(); | |
kmaJsonObject.addProperty(RetrofitClient.ServiceType.KMA_WEB_FORECASTS.name(), text); | |
} | |
} | |
rootJsonObject.add(weatherProviderType.name(), kmaJsonObject); | |
} else if (weatherProviderType == WeatherProviderType.ACCU_WEATHER) { | |
JsonObject accuJsonObject = new JsonObject(); | |
if (weatherDataTypeSet.contains(WeatherDataType.currentConditions)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.ACCU_CURRENT_CONDITIONS).getResponseText(); | |
accuJsonObject.addProperty(RetrofitClient.ServiceType.ACCU_CURRENT_CONDITIONS.name(), text); | |
} | |
if (weatherDataTypeSet.contains(WeatherDataType.hourlyForecast)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.ACCU_HOURLY_FORECAST).getResponseText(); | |
accuJsonObject.addProperty(RetrofitClient.ServiceType.ACCU_HOURLY_FORECAST.name(), text); | |
} | |
if (weatherDataTypeSet.contains(WeatherDataType.dailyForecast)) { | |
text = requestWeatherSourceArr.get(RetrofitClient.ServiceType.ACCU_DAILY_FORECAST).getResponseText(); | |
accuJsonObject.addProperty(RetrofitClient.ServiceType.ACCU_DAILY_FORECAST.name(), text); | |
} | |
rootJsonObject.add(weatherProviderType.name(), accuJsonObject); | |
} else if (weatherProviderType == WeatherProviderType.AQICN) { | |
JsonObject aqiCnJsonObject = new JsonObject(); | |
if (weatherDataTypeSet.contains(WeatherDataType.airQuality)) { | |
text = arrayMap.get(WeatherProviderType.AQICN).get(RetrofitClient.ServiceType.AQICN_GEOLOCALIZED_FEED).getResponseText(); | |
if (text != null && !text.equals("{}")) { | |
aqiCnJsonObject.addProperty(RetrofitClient.ServiceType.AQICN_GEOLOCALIZED_FEED.name(), text); | |
} | |
} | |
rootJsonObject.add(weatherProviderType.name(), aqiCnJsonObject); | |
} | |
} | |
if (zoneOffset != null) { | |
rootJsonObject.addProperty("zoneOffset", zoneOffset.getId()); | |
} | |
rootJsonObject.addProperty("lastUpdatedDateTime", weatherRestApiDownloader.getRequestDateTime().toString()); | |
widgetDto.setResponseText(rootJsonObject.toString()); | |
} | |
protected final void drawBitmap(ViewGroup rootLayout, @Nullable OnDrawBitmapCallback onDrawBitmapCallback, RemoteViews remoteViews, | |
@Nullable Integer parentWidth, @Nullable Integer parentHeight) { | |
int widthSize = 0; | |
int heightSize = 0; | |
if (parentWidth == null || parentHeight == null) { | |
int[] widgetSize = getWidgetExactSizeInPx(AppWidgetManager.getInstance(context)); | |
widthSize = widgetSize[0]; | |
heightSize = widgetSize[1]; | |
} else { | |
widthSize = parentWidth; | |
heightSize = parentHeight; | |
} | |
final float widgetPadding = context.getResources().getDimension(R.dimen.widget_padding); | |
final int widthSpec = View.MeasureSpec.makeMeasureSpec((int) (widthSize - widgetPadding * 2), EXACTLY); | |
final int heightSpec = View.MeasureSpec.makeMeasureSpec((int) (heightSize - widgetPadding * 2), EXACTLY); | |
rootLayout.measure(widthSpec, heightSpec); | |
Bitmap viewBmp = drawBitmap(rootLayout, remoteViews); | |
if (onDrawBitmapCallback != null) { | |
onDrawBitmapCallback.onCreatedBitmap(viewBmp); | |
} | |
} | |
protected final Bitmap drawBitmap(ViewGroup rootLayout, RemoteViews remoteViews) { | |
rootLayout.layout(0, 0, rootLayout.getMeasuredWidth(), rootLayout.getMeasuredHeight()); | |
rootLayout.setDrawingCacheEnabled(false); | |
rootLayout.destroyDrawingCache(); | |
rootLayout.setDrawingCacheEnabled(true); | |
rootLayout.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); | |
rootLayout.buildDrawingCache(); | |
Bitmap viewBmp = rootLayout.getDrawingCache(); | |
remoteViews.setImageViewBitmap(R.id.bitmapValuesView, viewBmp); | |
return viewBmp; | |
} | |
protected final RemoteViews createBaseRemoteViews() { | |
return new RemoteViews(context.getPackageName(), R.layout.view_widget); | |
} | |
public void setResultViews(int appWidgetId, | |
@Nullable @org.jetbrains.annotations.Nullable WeatherRestApiDownloader weatherRestApiDownloader, | |
@Nullable ZoneId zoneId) { | |
if (!widgetDto.isInitialized()) | |
widgetDto.setInitialized(true); | |
if (widgetDto.isLoadSuccessful()) { | |
widgetDto.setLastErrorType(null); | |
} else { | |
if (widgetDto.getLastErrorType() == null) | |
widgetDto.setLastErrorType(RemoteViewsUtil.ErrorType.FAILED_LOAD_WEATHER_DATA); | |
} | |
widgetRepository.update(widgetDto, new DbQueryCallback<WidgetDto>() { | |
@Override | |
public void onResultSuccessful(WidgetDto result) { | |
remoteViewsCallback.onResult(result.getAppWidgetId(), createRemoteViews()); | |
} | |
@Override | |
public void onResultNoData() { | |
} | |
}); | |
} | |
public RelativeLayout.LayoutParams getHeaderViewLayoutParams() { | |
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, | |
ViewGroup.LayoutParams.WRAP_CONTENT); | |
layoutParams.bottomMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4f, | |
context.getResources().getDisplayMetrics()); | |
return layoutParams; | |
} | |
protected View makeHeaderViews(LayoutInflater layoutInflater, String addressName, String lastRefreshDateTime) { | |
View view = layoutInflater.inflate(R.layout.header_view_in_widget, null, false); | |
((TextView) view.findViewById(R.id.address)).setText(addressName); | |
((TextView) view.findViewById(R.id.refresh)).setText(ZonedDateTime.parse(lastRefreshDateTime).format(refreshDateTimeFormatter)); | |
return view; | |
} | |
public RemoteViews createRemoteViews() { | |
RemoteViews remoteViews = createBaseRemoteViews(); | |
remoteViews.setOnClickPendingIntent(R.id.root_layout, getOnClickedPendingIntent()); | |
return remoteViews; | |
} | |
abstract public Class<?> widgetProviderClass(); | |
abstract public void setDisplayClock(boolean displayClock); | |
abstract public void setDataViewsOfSavedData(); | |
abstract public Set<WeatherDataType> getRequestWeatherDataTypeSet(); | |
public WidgetDto getWidgetDto() { | |
return widgetDto; | |
} | |
public int getAppWidgetId() { | |
return appWidgetId; | |
} | |
public interface WidgetUpdateCallback { | |
void updatePreview(); | |
} | |
public static abstract class RemoteViewsCallback { | |
private final int requestCount; | |
private final AtomicInteger responseCount = new AtomicInteger(0); | |
private final Map<Integer, RemoteViews> remoteViewsMap = new ConcurrentHashMap<>(); | |
public RemoteViewsCallback(int requestCount) { | |
this.requestCount = requestCount; | |
} | |
private void onResult(int id, RemoteViews remoteViews) { | |
remoteViewsMap.put(id, remoteViews); | |
if (responseCount.incrementAndGet() == requestCount) | |
onFinished(remoteViewsMap); | |
} | |
abstract protected void onFinished(Map<Integer, RemoteViews> remoteViewsMap); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lifedawn.bestweather.widget.widgetprovider; | |
import android.app.PendingIntent; | |
import android.appwidget.AppWidgetManager; | |
import android.appwidget.AppWidgetProvider; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.os.Bundle; | |
import android.util.Log; | |
import android.widget.RemoteViews; | |
import androidx.annotation.Nullable; | |
import androidx.work.Data; | |
import androidx.work.ExistingWorkPolicy; | |
import androidx.work.OneTimeWorkRequest; | |
import androidx.work.OutOfQuotaPolicy; | |
import androidx.work.WorkManager; | |
import com.lifedawn.bestweather.R; | |
import com.lifedawn.bestweather.commons.interfaces.BackgroundWorkCallback; | |
import com.lifedawn.bestweather.forremoteviews.RemoteViewsUtil; | |
import com.lifedawn.bestweather.main.MyApplication; | |
import com.lifedawn.bestweather.room.callback.DbQueryCallback; | |
import com.lifedawn.bestweather.room.dto.WidgetDto; | |
import com.lifedawn.bestweather.room.repository.WidgetRepository; | |
import com.lifedawn.bestweather.widget.WidgetHelper; | |
import com.lifedawn.bestweather.widget.creator.AbstractWidgetCreator; | |
import com.lifedawn.bestweather.widget.work.WidgetListenableWorker; | |
import java.util.Arrays; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.atomic.AtomicInteger; | |
public abstract class BaseAppWidgetProvider extends AppWidgetProvider { | |
protected void drawWidgets(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { | |
Executors.newSingleThreadExecutor().submit(() -> { | |
final String className = getClass().getName(); | |
final BackgroundWorkCallback backgroundWorkCallback = new BackgroundWorkCallback() { | |
final int requestCount = appWidgetIds.length; | |
final AtomicInteger responseCount = new AtomicInteger(0); | |
@Override | |
public void onFinished() { | |
int count = responseCount.incrementAndGet(); | |
Log.e(className, "위젯 그리기 : " + Arrays.toString(appWidgetIds) + ", 요청 : " + requestCount + ", 응답 : " + count); | |
if (count == requestCount) { | |
Log.e(className, "위젯 그리기 완료 : " + Arrays.toString(appWidgetIds)); | |
} | |
} | |
}; | |
for (int appWidgetId : appWidgetIds) { | |
if (appWidgetManager.getAppWidgetInfo(appWidgetId) == null) { | |
backgroundWorkCallback.onFinished(); | |
continue; | |
} | |
AbstractWidgetCreator widgetCreator = AbstractWidgetCreator.getInstance(appWidgetManager, context, appWidgetId); | |
widgetCreator.loadSavedSettings(new DbQueryCallback<WidgetDto>() { | |
@Override | |
public void onResultSuccessful(WidgetDto widgetDto) { | |
if (widgetDto != null) { | |
if (widgetDto.isInitialized()) { | |
if (widgetDto.isLoadSuccessful()) | |
widgetCreator.setDataViewsOfSavedData(); | |
else { | |
RemoteViews remoteViews = widgetCreator.createRemoteViews(); | |
widgetCreator.setRefreshPendingIntent(remoteViews); | |
RemoteViewsUtil.onErrorProcess(remoteViews, context, widgetDto.getLastErrorType()); | |
appWidgetManager.updateAppWidget(widgetCreator.getAppWidgetId(), remoteViews); | |
} | |
} | |
} | |
backgroundWorkCallback.onFinished(); | |
} | |
@Override | |
public void onResultNoData() { | |
backgroundWorkCallback.onFinished(); | |
} | |
}); | |
} | |
}); | |
} | |
@Override | |
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { | |
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); | |
} | |
@Override | |
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { | |
Log.e(getClass().getName(), Arrays.toString(appWidgetIds)); | |
if (!WidgetListenableWorker.processing.get()) | |
drawWidgets(context, appWidgetManager, appWidgetIds); | |
} | |
@Override | |
public void onEnabled(Context context) { | |
super.onEnabled(context); | |
} | |
@Override | |
public void onDisabled(Context context) { | |
super.onDisabled(context); | |
} | |
@Override | |
public void onDeleted(Context context, int[] appWidgetIds) { | |
super.onDeleted(context, appWidgetIds); | |
final BackgroundWorkCallback backgroundWorkCallback = new BackgroundWorkCallback() { | |
final int allDeletedCount = appWidgetIds.length; | |
final AtomicInteger deletedCount = new AtomicInteger(0); | |
@Override | |
public void onFinished() { | |
if (deletedCount.incrementAndGet() == allDeletedCount) { | |
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | |
if (appWidgetManager.getInstalledProviders().isEmpty()) { | |
WidgetHelper widgetHelper = new WidgetHelper(context); | |
widgetHelper.cancelAutoRefresh(); | |
} | |
} | |
} | |
}; | |
WidgetRepository widgetRepository = WidgetRepository.getINSTANCE(); | |
for (int appWidgetId : appWidgetIds) | |
widgetRepository.delete(appWidgetId, new DbQueryCallback<Boolean>() { | |
@Override | |
public void onResultSuccessful(Boolean result) { | |
backgroundWorkCallback.onFinished(); | |
} | |
@Override | |
public void onResultNoData() { | |
} | |
}); | |
} | |
@Override | |
public void onReceive(Context context, Intent intent) { | |
super.onReceive(context, intent); | |
final String action = intent.getAction(); | |
Log.e(getClass().getName(), action); | |
if (action != null) { | |
Bundle bundle = intent.getExtras(); | |
if (action.equals(context.getString(R.string.com_lifedawn_bestweather_action_INIT))) { | |
Data data = new Data.Builder().putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, | |
bundle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID)).build(); | |
startWork(context, action, data); | |
} else if (action.equals(context.getString(R.string.com_lifedawn_bestweather_action_REFRESH))) { | |
startWork(context, action, null); | |
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED) || action.equals(Intent.ACTION_MY_PACKAGE_REPLACED)) { | |
WidgetHelper widgetHelper = new WidgetHelper(context); | |
widgetHelper.reDrawWidgets(null); | |
} else if (action.equals(context.getString(R.string.com_lifedawn_bestweather_action_REDRAW))) { | |
int[] arr = bundle.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); | |
drawWidgets(context, AppWidgetManager.getInstance(context), arr); | |
} | |
} | |
} | |
protected void startWork(Context context, String action, @Nullable Data data) { | |
Data.Builder dataBuilder = new Data.Builder() | |
.putString("action", action); | |
if (data != null) | |
dataBuilder.putAll(data); | |
final String tag = "widget_" + action; | |
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(WidgetListenableWorker.class) | |
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) | |
.setInputData(dataBuilder.build()) | |
.addTag(tag) | |
.build(); | |
WorkManager workManager = WorkManager.getInstance(context); | |
workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lifedawn.bestweather.widget; | |
import androidx.activity.OnBackPressedCallback; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import androidx.appcompat.app.AppCompatActivity; | |
import androidx.core.app.ActivityCompat; | |
import androidx.fragment.app.Fragment; | |
import androidx.fragment.app.FragmentManager; | |
import androidx.preference.PreferenceManager; | |
import android.Manifest; | |
import android.annotation.SuppressLint; | |
import android.app.PendingIntent; | |
import android.app.WallpaperManager; | |
import android.appwidget.AppWidgetManager; | |
import android.appwidget.AppWidgetProviderInfo; | |
import android.content.ComponentName; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.content.SharedPreferences; | |
import android.content.pm.PackageManager; | |
import android.graphics.Color; | |
import android.graphics.drawable.Drawable; | |
import android.os.Bundle; | |
import android.util.TypedValue; | |
import android.view.View; | |
import android.view.ViewTreeObserver; | |
import android.view.Window; | |
import android.view.WindowManager; | |
import android.widget.AdapterView; | |
import android.widget.ArrayAdapter; | |
import android.widget.CompoundButton; | |
import android.widget.FrameLayout; | |
import android.widget.RadioGroup; | |
import android.widget.RemoteViews; | |
import android.widget.SeekBar; | |
import android.widget.SpinnerAdapter; | |
import android.widget.Toast; | |
import com.bumptech.glide.Glide; | |
import com.google.android.material.slider.Slider; | |
import com.lifedawn.bestweather.R; | |
import com.lifedawn.bestweather.commons.classes.MainThreadWorker; | |
import com.lifedawn.bestweather.commons.enums.BundleKey; | |
import com.lifedawn.bestweather.commons.enums.IntentRequestCodes; | |
import com.lifedawn.bestweather.commons.enums.LocationType; | |
import com.lifedawn.bestweather.commons.enums.WeatherProviderType; | |
import com.lifedawn.bestweather.databinding.ActivityConfigureWidgetBinding; | |
import com.lifedawn.bestweather.findaddress.map.MapFragment; | |
import com.lifedawn.bestweather.main.MyApplication; | |
import com.lifedawn.bestweather.room.callback.DbQueryCallback; | |
import com.lifedawn.bestweather.room.dto.FavoriteAddressDto; | |
import com.lifedawn.bestweather.room.dto.WidgetDto; | |
import com.lifedawn.bestweather.widget.creator.AbstractWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.EighthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.EleventhWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.FirstWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.NinthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.SecondWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.SeventhWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.SixthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.TenthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.ThirdWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.FourthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.FifthWidgetCreator; | |
import com.lifedawn.bestweather.widget.widgetprovider.EighthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.EleventhWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FirstWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.NinthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SecondWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SeventhWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SixthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.TenthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.ThirdWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FourthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FifthWidgetProvider; | |
import org.jetbrains.annotations.NotNull; | |
import java.util.List; | |
public class ConfigureWidgetActivity extends AppCompatActivity implements AbstractWidgetCreator.WidgetUpdateCallback { | |
private ActivityConfigureWidgetBinding binding; | |
private Integer appWidgetId; | |
private Integer layoutId; | |
private WidgetDto widgetDto; | |
private Long[] widgetRefreshIntervalValues; | |
private int originalWidgetRefreshIntervalValueIndex; | |
private int widgetRefreshIntervalValueIndex; | |
private int widgetHeight; | |
private int widgetWidth; | |
private FavoriteAddressDto newSelectedAddressDto; | |
private AbstractWidgetCreator widgetCreator; | |
private AppWidgetManager appWidgetManager; | |
private boolean selectedFavoriteLocation; | |
private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { | |
@Override | |
public void handleOnBackPressed() { | |
if (!getSupportFragmentManager().popBackStackImmediate()) { | |
setResult(RESULT_CANCELED); | |
finish(); | |
} | |
} | |
}; | |
private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks = new FragmentManager.FragmentLifecycleCallbacks() { | |
@Override | |
public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) { | |
super.onFragmentAttached(fm, f, context); | |
if (f instanceof MapFragment) { | |
binding.widgetSettingsContainer.setVisibility(View.GONE); | |
binding.fragmentContainer.setVisibility(View.VISIBLE); | |
} | |
} | |
@Override | |
public void onFragmentDestroyed(@NonNull @NotNull FragmentManager fm, @NonNull @NotNull Fragment f) { | |
super.onFragmentDestroyed(fm, f); | |
if (f instanceof MapFragment) { | |
binding.widgetSettingsContainer.setVisibility(View.VISIBLE); | |
binding.fragmentContainer.setVisibility(View.GONE); | |
} | |
} | |
}; | |
@Override | |
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { | |
super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
boolean denied = false; | |
for (int result : grantResults) { | |
if (result == PackageManager.PERMISSION_DENIED) { | |
denied = true; | |
break; | |
} | |
} | |
if (denied) { | |
binding.loadingAnimation.setVisibility(View.GONE); | |
} else { | |
setBackgroundImg(); | |
} | |
} | |
private void setBackgroundImg() { | |
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) | |
== PackageManager.PERMISSION_GRANTED) { | |
MyApplication.getExecutorService().submit(() -> { | |
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext()); | |
Drawable wallpaperDrawable = wallpaperManager.getDrawable(); | |
if (!isFinishing()) { | |
MainThreadWorker.runOnUiThread(() -> { | |
Glide.with(ConfigureWidgetActivity.this).load(wallpaperDrawable).into(binding.wallpaper); | |
binding.loadingAnimation.setVisibility(View.GONE); | |
}); | |
} | |
}); | |
} else { | |
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 3); | |
} | |
} | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
binding = ActivityConfigureWidgetBinding.inflate(getLayoutInflater()); | |
setContentView(binding.getRoot()); | |
binding.displayDatetimeSwitch.setVisibility(View.GONE); | |
binding.displayLocalDatetimeSwitch.setVisibility(View.GONE); | |
getSupportFragmentManager().registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false); | |
getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback); | |
Bundle bundle = getIntent().getExtras(); | |
if (bundle != null) { | |
appWidgetId = bundle.getInt( | |
AppWidgetManager.EXTRA_APPWIDGET_ID, | |
AppWidgetManager.INVALID_APPWIDGET_ID); | |
} | |
appWidgetManager = AppWidgetManager.getInstance(this); | |
final AppWidgetProviderInfo appWidgetProviderInfo = appWidgetManager.getAppWidgetInfo(appWidgetId); | |
layoutId = appWidgetProviderInfo.initialLayout; | |
ComponentName componentName = appWidgetProviderInfo.provider; | |
final String widgetProviderClassName = componentName.getClassName(); | |
if (widgetProviderClassName.equals(FirstWidgetProvider.class.getName())) { | |
widgetCreator = new FirstWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(SecondWidgetProvider.class.getName())) { | |
widgetCreator = new SecondWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(ThirdWidgetProvider.class.getName())) { | |
widgetCreator = new ThirdWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(FourthWidgetProvider.class.getName())) { | |
widgetCreator = new FourthWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(FifthWidgetProvider.class.getName())) { | |
widgetCreator = new FifthWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(SixthWidgetProvider.class.getName())) { | |
widgetCreator = new SixthWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(SeventhWidgetProvider.class.getName())) { | |
widgetCreator = new SeventhWidgetCreator(getApplicationContext(), this, appWidgetId); | |
binding.weatherDataSourceLayout.setVisibility(View.GONE); | |
} else if (widgetProviderClassName.equals(EighthWidgetProvider.class.getName())) { | |
widgetCreator = new EighthWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(NinthWidgetProvider.class.getName())) { | |
widgetCreator = new NinthWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(TenthWidgetProvider.class.getName())) { | |
widgetCreator = new TenthWidgetCreator(getApplicationContext(), this, appWidgetId); | |
} else if (widgetProviderClassName.equals(EleventhWidgetProvider.class.getName())) { | |
widgetCreator = new EleventhWidgetCreator(getApplicationContext(), this, appWidgetId); | |
binding.kmaTopPrioritySwitch.setText(R.string.containsKma); | |
binding.weatherDataSourceLayout.setVisibility(View.GONE); | |
} | |
widgetDto = widgetCreator.loadDefaultSettings(); | |
widgetHeight = (int) (appWidgetProviderInfo.minHeight * 1.9); | |
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) binding.previewLayout.getLayoutParams(); | |
layoutParams.topMargin = MyApplication.getStatusBarHeight() + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f, | |
getResources().getDisplayMetrics()); | |
layoutParams.height = widgetHeight; | |
binding.previewLayout.setLayoutParams(layoutParams); | |
//위치, 날씨제공사, 대한민국 최우선, 자동 업데이트 간격, 날짜와 시각표시, | |
//현지 시각으로 표시, 글자크기, 배경 투명도 | |
initLocation(); | |
initWeatherProvider(); | |
initAutoRefreshInterval(); | |
initDisplayDateTime(); | |
initTextSize(); | |
initBackground(); | |
setBackgroundImg(); | |
binding.currentLocationRadio.setChecked(true); | |
binding.save.setOnClickListener(v -> widgetCreator.saveSettings(widgetDto, new DbQueryCallback<WidgetDto>() { | |
@Override | |
public void onResultSuccessful(WidgetDto result) { | |
MainThreadWorker.runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
if (originalWidgetRefreshIntervalValueIndex != widgetRefreshIntervalValueIndex) { | |
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()) | |
.edit().putLong(getString(R.string.pref_key_widget_refresh_interval), | |
widgetRefreshIntervalValues[widgetRefreshIntervalValueIndex]).commit(); | |
WidgetHelper widgetHelper = new WidgetHelper(getApplicationContext()); | |
widgetHelper.onSelectedAutoRefreshInterval(widgetRefreshIntervalValues[widgetRefreshIntervalValueIndex]); | |
} | |
Intent resultValue = new Intent(); | |
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); | |
setResult(RESULT_OK, resultValue); | |
Bundle initBundle = new Bundle(); | |
initBundle.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); | |
Intent intent = new Intent(getApplicationContext(), widgetCreator.widgetProviderClass()); | |
intent.setAction(getString(R.string.com_lifedawn_bestweather_action_INIT)); | |
intent.putExtras(initBundle); | |
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), IntentRequestCodes.WIDGET_MANUALLY_REFRESH.requestCode, | |
intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); | |
try { | |
pendingIntent.send(); | |
} catch (PendingIntent.CanceledException e) { | |
e.printStackTrace(); | |
} | |
finishAndRemoveTask(); | |
} | |
}); | |
} | |
@Override | |
public void onResultNoData() { | |
} | |
})); | |
binding.getRoot().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { | |
@Override | |
public void onGlobalLayout() { | |
binding.getRoot().getViewTreeObserver().removeOnGlobalLayoutListener(this); | |
widgetWidth = binding.previewLayout.getWidth(); | |
updatePreview(); | |
} | |
}); | |
} | |
private void initBackground() { | |
binding.backgroundTransparencySlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { | |
@Override | |
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { | |
setBackgroundAlpha(progress); | |
} | |
@Override | |
public void onStartTrackingTouch(SeekBar seekBar) { | |
setBackgroundAlpha(seekBar.getProgress()); | |
} | |
@Override | |
public void onStopTrackingTouch(SeekBar seekBar) { | |
setBackgroundAlpha(seekBar.getProgress()); | |
} | |
}); | |
} | |
private void initTextSize() { | |
binding.textSizeSlider.addOnSliderTouchListener(new Slider.OnSliderTouchListener() { | |
@SuppressLint("RestrictedApi") | |
@Override | |
public void onStartTrackingTouch(@NonNull Slider slider) { | |
setTextSizeInWidget((int) slider.getValue()); | |
} | |
@SuppressLint("RestrictedApi") | |
@Override | |
public void onStopTrackingTouch(@NonNull Slider slider) { | |
setTextSizeInWidget((int) slider.getValue()); | |
} | |
}); | |
} | |
private void initDisplayDateTime() { | |
binding.displayDatetimeSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | |
@Override | |
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | |
binding.displayLocalDatetimeSwitch.setVisibility(isChecked ? View.VISIBLE : View.GONE); | |
widgetDto.setDisplayClock(isChecked); | |
updatePreview(); | |
} | |
}); | |
binding.displayLocalDatetimeSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | |
@Override | |
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | |
widgetDto.setDisplayLocalClock(isChecked); | |
} | |
}); | |
} | |
private void initAutoRefreshInterval() { | |
final String[] intervalsDescription = getResources().getStringArray(R.array.AutoRefreshIntervals); | |
final String[] intervalsStr = getResources().getStringArray(R.array.AutoRefreshIntervalsLong); | |
widgetRefreshIntervalValues = new Long[intervalsStr.length]; | |
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); | |
Long currentValue = sharedPreferences.getLong(getString(R.string.pref_key_widget_refresh_interval), 0L); | |
for (int i = 0; i < intervalsStr.length; i++) { | |
widgetRefreshIntervalValues[i] = Long.parseLong(intervalsStr[i]); | |
} | |
SpinnerAdapter spinnerAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, intervalsDescription); | |
binding.autoRefreshIntervalSpinner.setAdapter(spinnerAdapter); | |
binding.autoRefreshIntervalSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { | |
@Override | |
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { | |
widgetRefreshIntervalValueIndex = position; | |
} | |
@Override | |
public void onNothingSelected(AdapterView<?> parent) { | |
} | |
}); | |
widgetRefreshIntervalValueIndex = 0; | |
for (String v : intervalsStr) { | |
if (currentValue.toString().equals(v)) { | |
break; | |
} | |
widgetRefreshIntervalValueIndex++; | |
} | |
originalWidgetRefreshIntervalValueIndex = widgetRefreshIntervalValueIndex; | |
binding.autoRefreshIntervalSpinner.setSelection(widgetRefreshIntervalValueIndex); | |
} | |
private void initWeatherProvider() { | |
binding.weatherDataSourceRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { | |
@Override | |
public void onCheckedChanged(RadioGroup group, int checkedId) { | |
widgetDto.addWeatherProviderType(checkedId == R.id.owm_radio ? WeatherProviderType.OWM_ONECALL : WeatherProviderType.MET_NORWAY); | |
} | |
}); | |
binding.kmaTopPrioritySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | |
@Override | |
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | |
widgetDto.setTopPriorityKma(isChecked); | |
} | |
}); | |
if (PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getBoolean(getString(R.string.pref_key_open_weather_map), false)) { | |
binding.owmRadio.setChecked(true); | |
} else { | |
binding.metNorwayRadio.setChecked(true); | |
} | |
} | |
private void initLocation() { | |
binding.changeAddressBtn.setVisibility(View.GONE); | |
binding.selectedAddressName.setVisibility(View.GONE); | |
binding.locationRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { | |
if (checkedId == binding.currentLocationRadio.getId() && binding.currentLocationRadio.isChecked()) { | |
binding.changeAddressBtn.setVisibility(View.GONE); | |
binding.selectedAddressName.setVisibility(View.GONE); | |
widgetDto.setLocationType(LocationType.CurrentLocation); | |
} else if (checkedId == binding.selectedLocationRadio.getId() && binding.selectedLocationRadio.isChecked()) { | |
binding.changeAddressBtn.setVisibility(View.VISIBLE); | |
binding.selectedAddressName.setVisibility(View.VISIBLE); | |
widgetDto.setLocationType(LocationType.SelectedAddress); | |
if (!selectedFavoriteLocation) { | |
openFavoritesFragment(); | |
} | |
} | |
}); | |
binding.changeAddressBtn.setOnClickListener(v -> openFavoritesFragment()); | |
} | |
private void openFavoritesFragment() { | |
MapFragment mapFragment = new MapFragment(); | |
Bundle bundle = new Bundle(); | |
bundle.putString(BundleKey.RequestFragment.name(), ConfigureWidgetActivity.class.getName()); | |
mapFragment.setArguments(bundle); | |
mapFragment.setOnResultFavoriteListener(new MapFragment.OnResultFavoriteListener() { | |
@Override | |
public void onAddedNewAddress(FavoriteAddressDto newFavoriteAddressDto, List<FavoriteAddressDto> favoriteAddressDtoList, boolean removed) { | |
onClickedAddress(newFavoriteAddressDto); | |
getSupportFragmentManager().popBackStack(); | |
} | |
@Override | |
public void onResult(List<FavoriteAddressDto> favoriteAddressDtoList) { | |
} | |
@Override | |
public void onClickedAddress(@Nullable FavoriteAddressDto favoriteSelectedAddressDto) { | |
if (favoriteSelectedAddressDto == null) { | |
if (!selectedFavoriteLocation) { | |
Toast.makeText(getApplicationContext(), R.string.not_selected_address, Toast.LENGTH_SHORT).show(); | |
binding.currentLocationRadio.setChecked(true); | |
} | |
} else { | |
selectedFavoriteLocation = true; | |
newSelectedAddressDto = favoriteSelectedAddressDto; | |
WidgetDto widgetDto = widgetCreator.getWidgetDto(); | |
widgetDto.setAddressName(newSelectedAddressDto.getDisplayName()); | |
widgetDto.setCountryCode(newSelectedAddressDto.getCountryCode()); | |
widgetDto.setLatitude(Double.parseDouble(newSelectedAddressDto.getLatitude())); | |
widgetDto.setLongitude(Double.parseDouble(newSelectedAddressDto.getLongitude())); | |
widgetDto.setTimeZoneId(newSelectedAddressDto.getZoneId()); | |
binding.selectedAddressName.setText(newSelectedAddressDto.getDisplayName()); | |
getSupportFragmentManager().popBackStack(); | |
} | |
} | |
}); | |
String tag = com.lifedawn.bestweather.findaddress.map.MapFragment.class.getName(); | |
getSupportFragmentManager().beginTransaction().add(binding.fragmentContainer.getId(), mapFragment, tag) | |
.addToBackStack(tag).commitAllowingStateLoss(); | |
} | |
private void setTextSizeInWidget(int value) { | |
//widgetCreator.setTextSize(value); | |
//updatePreview(); | |
} | |
private void setBackgroundAlpha(int alpha) { | |
widgetDto.setBackgroundAlpha(100 - alpha); | |
updatePreview(); | |
} | |
@Override | |
public void updatePreview() { | |
binding.previewLayout.removeAllViews(); | |
RemoteViews removeViews = widgetCreator.createTempViews(widgetWidth, widgetHeight); | |
View view = removeViews.apply(getApplicationContext(), binding.previewLayout); | |
binding.previewLayout.addView(view); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lifedawn.bestweather.widget; | |
import androidx.appcompat.app.AlertDialog; | |
import androidx.preference.PreferenceManager; | |
import android.app.Activity; | |
import android.app.PendingIntent; | |
import android.appwidget.AppWidgetManager; | |
import android.appwidget.AppWidgetProviderInfo; | |
import android.content.ComponentName; | |
import android.content.DialogInterface; | |
import android.content.Intent; | |
import android.content.SharedPreferences; | |
import android.graphics.Color; | |
import android.graphics.drawable.ColorDrawable; | |
import android.os.Bundle; | |
import android.view.ContextThemeWrapper; | |
import android.view.View; | |
import android.widget.TextView; | |
import com.lifedawn.bestweather.R; | |
import com.lifedawn.bestweather.commons.classes.MainThreadWorker; | |
import com.lifedawn.bestweather.databinding.ActivityDialogBinding; | |
import com.lifedawn.bestweather.main.MainActivity; | |
import com.lifedawn.bestweather.room.callback.DbQueryCallback; | |
import com.lifedawn.bestweather.room.dto.WidgetDto; | |
import com.lifedawn.bestweather.widget.creator.AbstractWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.EighthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.EleventhWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.FirstWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.NinthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.SecondWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.SeventhWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.SixthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.TenthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.ThirdWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.FourthWidgetCreator; | |
import com.lifedawn.bestweather.widget.creator.FifthWidgetCreator; | |
import com.lifedawn.bestweather.widget.widgetprovider.EighthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.EleventhWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FirstWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.NinthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SecondWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SeventhWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.SixthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.TenthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.ThirdWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FourthWidgetProvider; | |
import com.lifedawn.bestweather.widget.widgetprovider.FifthWidgetProvider; | |
public class DialogActivity extends Activity { | |
private ActivityDialogBinding binding; | |
private int appWidgetId; | |
private AbstractWidgetCreator widgetCreator; | |
private AlertDialog alertDialog; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
getWindow().setBackgroundDrawable(new ColorDrawable(0)); | |
binding = ActivityDialogBinding.inflate(getLayoutInflater()); | |
setContentView(binding.getRoot()); | |
Bundle bundle = getIntent().getExtras(); | |
appWidgetId = bundle.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID); | |
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); | |
final AppWidgetProviderInfo appWidgetProviderInfo = appWidgetManager.getAppWidgetInfo(appWidgetId); | |
ComponentName componentName = appWidgetProviderInfo.provider; | |
final String providerClassName = componentName.getClassName(); | |
if (providerClassName.equals(FirstWidgetProvider.class.getName())) { | |
widgetCreator = new FirstWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(SecondWidgetProvider.class.getName())) { | |
widgetCreator = new SecondWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(ThirdWidgetProvider.class.getName())) { | |
widgetCreator = new ThirdWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(FourthWidgetProvider.class.getName())) { | |
widgetCreator = new FourthWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(FifthWidgetProvider.class.getName())) { | |
widgetCreator = new FifthWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(SixthWidgetProvider.class.getName())) { | |
widgetCreator = new SixthWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(SeventhWidgetProvider.class.getName())) { | |
widgetCreator = new SeventhWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(EighthWidgetProvider.class.getName())) { | |
widgetCreator = new EighthWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(NinthWidgetProvider.class.getName())) { | |
widgetCreator = new NinthWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(TenthWidgetProvider.class.getName())) { | |
widgetCreator = new TenthWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} else if (providerClassName.equals(EleventhWidgetProvider.class.getName())) { | |
widgetCreator = new EleventhWidgetCreator(getApplicationContext(), null, appWidgetId); | |
} | |
final Class<?> widgetProviderClass = widgetCreator.widgetProviderClass(); | |
final View dialogView = getLayoutInflater().inflate(R.layout.view_widget_dialog, null); | |
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); | |
final Long refreshInterval = sharedPreferences.getLong(getString(R.string.pref_key_widget_refresh_interval), 0L); | |
String refreshIntervalText = null; | |
if (refreshInterval > 0) { | |
String[] autoRefreshIntervalsValue = getResources().getStringArray(R.array.AutoRefreshIntervalsLong); | |
String[] autoRefreshIntervalsText = getResources().getStringArray(R.array.AutoRefreshIntervals); | |
for (int i = 0; i < autoRefreshIntervalsValue.length; i++) { | |
if (refreshInterval.toString().equals(autoRefreshIntervalsValue[i])) { | |
refreshIntervalText = autoRefreshIntervalsText[i]; | |
break; | |
} | |
} | |
} else { | |
refreshIntervalText = getString(R.string.disable_auto_refresh); | |
} | |
((TextView) dialogView.findViewById(R.id.auto_refresh_interval)).setText(refreshIntervalText); | |
((TextView) dialogView.findViewById(R.id.widgetTypeName)).setText(appWidgetProviderInfo.loadLabel(getPackageManager())); | |
((TextView) dialogView.findViewById(R.id.openAppBtn)).setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
Intent intent = new Intent(getApplicationContext(), MainActivity.class); | |
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); | |
alertDialog.dismiss(); | |
startActivity(intent); | |
finish(); | |
} | |
}); | |
((TextView) dialogView.findViewById(R.id.updateBtn)).setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
PendingIntent pendingIntent = widgetCreator.getRefreshPendingIntent(); | |
try { | |
pendingIntent.send(); | |
} catch (PendingIntent.CanceledException e) { | |
e.printStackTrace(); | |
} | |
alertDialog.dismiss(); | |
finish(); | |
} | |
}); | |
((TextView) dialogView.findViewById(R.id.cancelBtn)).setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
alertDialog.dismiss(); | |
finish(); | |
} | |
}); | |
widgetCreator.loadSavedSettings(new DbQueryCallback<WidgetDto>() { | |
@Override | |
public void onResultSuccessful(WidgetDto result) { | |
MainThreadWorker.runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
if (DialogActivity.this.isFinishing() || DialogActivity.this.isDestroyed()) { | |
return; | |
} | |
alertDialog = new AlertDialog.Builder(new ContextThemeWrapper(DialogActivity.this, | |
R.style.Theme_AppCompat_Light_Dialog)) | |
.setCancelable(true) | |
.setOnCancelListener(new DialogInterface.OnCancelListener() { | |
@Override | |
public void onCancel(DialogInterface dialog) { | |
dialog.dismiss(); | |
finish(); | |
} | |
}) | |
.setView(dialogView) | |
.create(); | |
alertDialog.show(); | |
alertDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); | |
} | |
}); | |
} | |
@Override | |
public void onResultNoData() { | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" | |
android:configure="com.lifedawn.bestweather.widget.ConfigureWidgetActivity" | |
android:initialLayout="@layout/view_widget" | |
android:minWidth="@dimen/ninthWidgetWidth" | |
android:minHeight="@dimen/ninthWidgetHeight" | |
android:minResizeWidth="@dimen/ninthWidgetWidth" | |
android:minResizeHeight="@dimen/ninthWidgetHeight" | |
android:previewImage="@drawable/widget_preview_9" | |
android:resizeMode="vertical|horizontal" | |
android:updatePeriodMillis="0" | |
android:widgetCategory="home_screen" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lifedawn.bestweather.widget.creator; | |
import android.appwidget.AppWidgetManager; | |
import android.content.Context; | |
import android.view.Gravity; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.ImageView; | |
import android.widget.LinearLayout; | |
import android.widget.RelativeLayout; | |
import android.widget.RemoteViews; | |
import android.widget.TextView; | |
import androidx.annotation.Nullable; | |
import com.google.gson.JsonObject; | |
import com.google.gson.JsonParser; | |
import com.lifedawn.bestweather.R; | |
import com.lifedawn.bestweather.commons.enums.WeatherProviderType; | |
import com.lifedawn.bestweather.commons.enums.WeatherDataType; | |
import com.lifedawn.bestweather.forremoteviews.RemoteViewsUtil; | |
import com.lifedawn.bestweather.retrofit.util.WeatherRestApiDownloader; | |
import com.lifedawn.bestweather.weathers.dataprocessing.response.WeatherResponseProcessor; | |
import com.lifedawn.bestweather.weathers.dataprocessing.util.WeatherRequestUtil; | |
import com.lifedawn.bestweather.weathers.models.HourlyForecastDto; | |
import com.lifedawn.bestweather.weathers.view.DetailSingleTemperatureView; | |
import com.lifedawn.bestweather.widget.OnDrawBitmapCallback; | |
import com.lifedawn.bestweather.widget.widgetprovider.NinthWidgetProvider; | |
import java.time.ZoneId; | |
import java.time.ZoneOffset; | |
import java.time.ZonedDateTime; | |
import java.time.format.DateTimeFormatter; | |
import java.util.ArrayList; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Set; | |
public class NinthWidgetCreator extends AbstractWidgetCreator { | |
private final int hourGap = 3; | |
private final int maxHoursCount = 13; | |
public NinthWidgetCreator(Context context, WidgetUpdateCallback widgetUpdateCallback, int appWidgetId) { | |
super(context, widgetUpdateCallback, appWidgetId); | |
} | |
@Override | |
public Set<WeatherDataType> getRequestWeatherDataTypeSet() { | |
Set<WeatherDataType> set = new HashSet<>(); | |
set.add(WeatherDataType.hourlyForecast); | |
return set; | |
} | |
@Override | |
public RemoteViews createTempViews(Integer parentWidth, Integer parentHeight) { | |
RemoteViews remoteViews = createBaseRemoteViews(); | |
RemoteViewsUtil.onSuccessfulProcess(remoteViews); | |
drawViews(remoteViews, context.getString(R.string.address_name), ZonedDateTime.now().toString(), | |
WeatherResponseProcessor.getTempHourlyForecastDtoList(context, 24), | |
null, parentWidth, parentHeight); | |
return remoteViews; | |
} | |
@Override | |
public Class<?> widgetProviderClass() { | |
return NinthWidgetProvider.class; | |
} | |
public void setDataViews(RemoteViews remoteViews, String addressName, String lastRefreshDateTime, | |
List<HourlyForecastDto> hourlyForecastDtoList, OnDrawBitmapCallback onDrawBitmapCallback) { | |
drawViews(remoteViews, addressName, lastRefreshDateTime, hourlyForecastDtoList, onDrawBitmapCallback, null, null); | |
} | |
private void drawViews(RemoteViews remoteViews, String addressName, String lastRefreshDateTime, | |
List<HourlyForecastDto> hourlyForecastDtoList, @Nullable OnDrawBitmapCallback onDrawBitmapCallback, @Nullable Integer parentWidth, | |
@Nullable Integer parentHeight) { | |
RelativeLayout rootLayout = new RelativeLayout(context); | |
LinearLayout hourAndIconLinearLayout = new LinearLayout(context); | |
hourAndIconLinearLayout.setId(R.id.hourAndIconView); | |
hourAndIconLinearLayout.setOrientation(LinearLayout.HORIZONTAL); | |
LinearLayout.LayoutParams hourAndIconCellLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); | |
hourAndIconCellLayoutParams.gravity = Gravity.CENTER; | |
hourAndIconCellLayoutParams.weight = 1; | |
LayoutInflater layoutInflater = LayoutInflater.from(context); | |
View headerView = makeHeaderViews(layoutInflater, addressName, lastRefreshDateTime); | |
headerView.setId(R.id.header); | |
List<Integer> tempList = new ArrayList<>(); | |
final String degree = tempDegree; | |
DateTimeFormatter hour0Formatter = DateTimeFormatter.ofPattern("E\n0"); | |
DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("E\nH"); | |
//강우, 강설 여부 확인 | |
boolean haveSnowVolume = false; | |
boolean haveRainVolume = false; | |
int count = 1; | |
int cell = 0; | |
for (; cell < hourlyForecastDtoList.size(); cell = cell + hourGap) { | |
if (count > maxHoursCount) { | |
break; | |
} | |
if (hourlyForecastDtoList.get(cell).isHasSnow()) { | |
haveSnowVolume = true; | |
} | |
if (hourlyForecastDtoList.get(cell).isHasRain() || hourlyForecastDtoList.get(cell).isHasPrecipitation()) { | |
haveRainVolume = true; | |
} | |
count++; | |
} | |
count = 1; | |
for (cell = 0; cell < hourlyForecastDtoList.size(); cell = cell + hourGap) { | |
if (count++ > maxHoursCount) { | |
break; | |
} | |
View view = layoutInflater.inflate(R.layout.view_forecast_item_in_linear, null, false); | |
if (hourlyForecastDtoList.get(cell).getHours().getHour() == 0) { | |
((TextView) view.findViewById(R.id.dateTime)).setText(hourlyForecastDtoList.get(cell).getHours().format(hour0Formatter)); | |
} else { | |
((TextView) view.findViewById(R.id.dateTime)).setText(hourlyForecastDtoList.get(cell).getHours().format(hourFormatter)); | |
} | |
((ImageView) view.findViewById(R.id.leftIcon)).setImageResource(hourlyForecastDtoList.get(cell).getWeatherIcon()); | |
view.findViewById(R.id.temperature).setVisibility(View.GONE); | |
view.findViewById(R.id.rightIcon).setVisibility(View.GONE); | |
view.findViewById(R.id.popLayout).setVisibility(View.GONE); | |
view.findViewById(R.id.rainVolumeLayout).setVisibility(View.GONE); | |
view.findViewById(R.id.snowVolumeLayout).setVisibility(View.GONE); | |
tempList.add(Integer.parseInt(hourlyForecastDtoList.get(cell).getTemp().replace(degree, ""))); | |
hourAndIconLinearLayout.addView(view, hourAndIconCellLayoutParams); | |
} | |
RelativeLayout.LayoutParams headerViewLayoutParams = getHeaderViewLayoutParams(); | |
RelativeLayout.LayoutParams hourAndIconRowLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, | |
ViewGroup.LayoutParams.WRAP_CONTENT); | |
RelativeLayout.LayoutParams tempRowLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, | |
ViewGroup.LayoutParams.MATCH_PARENT); | |
headerViewLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); | |
hourAndIconRowLayoutParams.addRule(RelativeLayout.BELOW, R.id.header); | |
tempRowLayoutParams.addRule(RelativeLayout.BELOW, R.id.hourAndIconView); | |
tempRowLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); | |
DetailSingleTemperatureView detailSingleTemperatureView = new DetailSingleTemperatureView(context, tempList); | |
rootLayout.addView(headerView, headerViewLayoutParams); | |
rootLayout.addView(hourAndIconLinearLayout, hourAndIconRowLayoutParams); | |
rootLayout.addView(detailSingleTemperatureView, tempRowLayoutParams); | |
drawBitmap(rootLayout, onDrawBitmapCallback, remoteViews, parentWidth, parentHeight); | |
} | |
@Override | |
public void setDisplayClock(boolean displayClock) { | |
widgetDto.setDisplayClock(displayClock); | |
} | |
@Override | |
public void setDataViewsOfSavedData() { | |
WeatherProviderType weatherProviderType = WeatherResponseProcessor.getMainWeatherSourceType(widgetDto.getWeatherProviderTypeSet()); | |
if (widgetDto.isTopPriorityKma() && widgetDto.getCountryCode().equals("KR")) { | |
weatherProviderType = WeatherProviderType.KMA_WEB; | |
} | |
WeatherRequestUtil.initWeatherSourceUniqueValues(weatherProviderType, true, context); | |
RemoteViews remoteViews = createRemoteViews(); | |
zoneId = ZoneId.of(widgetDto.getTimeZoneId()); | |
JsonObject jsonObject = (JsonObject) JsonParser.parseString(widgetDto.getResponseText()); | |
WeatherRequestUtil.initWeatherSourceUniqueValues(weatherProviderType, false, context); | |
List<HourlyForecastDto> hourlyForecastDtoList = WeatherResponseProcessor.parseTextToHourlyForecastDtoList(context, jsonObject, | |
weatherProviderType, widgetDto.getLatitude(), widgetDto.getLongitude(), zoneId); | |
setDataViews(remoteViews, widgetDto.getAddressName(), widgetDto.getLastRefreshDateTime(), | |
hourlyForecastDtoList, null); | |
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | |
RemoteViewsUtil.onSuccessfulProcess(remoteViews); | |
appWidgetManager.updateAppWidget(appWidgetId, remoteViews); | |
} | |
@Override | |
public void setResultViews(int appWidgetId, @Nullable @org.jetbrains.annotations.Nullable WeatherRestApiDownloader weatherRestApiDownloader, ZoneId zoneId) { | |
this.zoneId = zoneId; | |
final List<HourlyForecastDto> hourlyForecastDtoList = WeatherResponseProcessor.getHourlyForecastDtoList(context, weatherRestApiDownloader, | |
WeatherResponseProcessor.getMainWeatherSourceType(widgetDto.getWeatherProviderTypeSet()), zoneId); | |
final boolean successful = !hourlyForecastDtoList.isEmpty(); | |
if (successful) { | |
ZoneOffset zoneOffset = hourlyForecastDtoList.get(0).getHours().getOffset(); | |
widgetDto.setTimeZoneId(zoneId.getId()); | |
widgetDto.setLastRefreshDateTime(weatherRestApiDownloader.getRequestDateTime().toString()); | |
makeResponseTextToJson(weatherRestApiDownloader, getRequestWeatherDataTypeSet(), widgetDto.getWeatherProviderTypeSet(), widgetDto, zoneOffset); | |
} | |
widgetDto.setLoadSuccessful(successful); | |
super.setResultViews(appWidgetId, weatherRestApiDownloader, zoneId); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lifedawn.bestweather.widget.widgetprovider; | |
import android.appwidget.AppWidgetManager; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.os.Bundle; | |
public class NinthWidgetProvider extends BaseAppWidgetProvider { | |
@Override | |
public void onEnabled(Context context) { | |
super.onEnabled(context); | |
} | |
@Override | |
public void onDisabled(Context context) { | |
super.onDisabled(context); | |
} | |
@Override | |
public void onDeleted(Context context, int[] appWidgetIds) { | |
super.onDeleted(context, appWidgetIds); | |
} | |
@Override | |
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { | |
super.onUpdate(context, appWidgetManager, appWidgetIds); | |
} | |
@Override | |
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { | |
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); | |
} | |
@Override | |
public void onReceive(Context context, Intent intent) { | |
super.onReceive(context, intent); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:id="@+id/root_layout" | |
style="@style/WidgetBackground" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_gravity="center" | |
android:clickable="true" | |
android:focusable="true" | |
> | |
<FrameLayout | |
android:id="@+id/valuesLayout" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_alignParentLeft="true" | |
android:layout_alignParentTop="true" | |
android:layout_alignParentRight="true" | |
android:layout_alignParentBottom="true" | |
android:gravity="center" | |
android:visibility="gone" | |
> | |
<FrameLayout | |
android:id="@+id/noBitmapValuesView" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:visibility="gone" | |
/> | |
<ImageView | |
android:id="@+id/bitmapValuesView" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
tools:ignore="ContentDescription" | |
/> | |
</FrameLayout> | |
<ProgressBar | |
android:id="@+id/progressbar" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_centerInParent="true" | |
android:indeterminate="true" | |
android:indeterminateTint="@color/blue" | |
/> | |
<include | |
layout="@layout/layout_warning_for_remoteviews" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_centerInParent="true" | |
android:visibility="gone" | |
/> | |
</RelativeLayout> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment