package de.theknut.xposedgelsettings.hooks.googlesearchbar.weatherwidget;
import android.content.res.Configuration;
import android.graphics.Color;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Locale;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import de.theknut.xposedgelsettings.R;
import de.theknut.xposedgelsettings.hooks.Common;
import de.theknut.xposedgelsettings.hooks.HooksBaseClass;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Classes;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Fields;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Methods;
import de.theknut.xposedgelsettings.hooks.PreferencesHelper;
import de.theknut.xposedgelsettings.hooks.Utils;
import de.theknut.xposedgelsettings.hooks.common.CommonHooks;
import de.theknut.xposedgelsettings.hooks.common.XGELSCallback;
import de.theknut.xposedgelsettings.hooks.googlesearchbar.GetWorkspacePaddingHook;
import static de.robv.android.xposed.XposedBridge.hookAllConstructors;
import static de.robv.android.xposed.XposedHelpers.callMethod;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import static de.robv.android.xposed.XposedHelpers.findClass;
import static de.robv.android.xposed.XposedHelpers.getFloatField;
import static de.robv.android.xposed.XposedHelpers.getIntField;
import static de.robv.android.xposed.XposedHelpers.getObjectField;
/**
* Created by Alexander Schulz on 17.10.2014.
*/
public class WeatherWidget extends HooksBaseClass {
static Object weatherEntry;
private static LinearLayout widget;
private static LinearLayout widgetContentHolder;
static View ospc;
static WidgetSettings widgetSettings = new WidgetSettings();
public static void initAllHooks(final LoadPackageParam lpparam) {
if (false && !PreferencesHelper.hideSearchBar && Common.PACKAGE_OBFUSCATED) {
if (PreferencesHelper.searchBarWeatherWidget) {
hookAllConstructors(Classes.WeatherPoint, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
weatherEntry = param.thisObject;
}
});
findAndHookMethod(Classes.WeatherEntryAdapter, Methods.weaUpdateWeather, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
maybeAddWidget();
final Animation fadeOut = AnimationUtils.loadAnimation(Common.XGELS_CONTEXT, R.anim.weather_fade_out);
fadeOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
widget.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationEnd(Animation animation) {
widget.setVisibility(View.VISIBLE);
updateWeatherContent();
widget.startAnimation(AnimationUtils.loadAnimation(Common.XGELS_CONTEXT, R.anim.weather_fade_in));
}
@Override
public void onAnimationRepeat(Animation animation) { }
});
if (((Boolean) callMethod(Common.LAUNCHER_INSTANCE, Methods.lIsAllAppsVisible) // workspace state is not normal
|| !getObjectField(Common.WORKSPACE_INSTANCE, Fields.wState).toString().equals("NORMAL"))
|| ((Boolean) callMethod(Common.LAUNCHER_INSTANCE, Methods.lHasCustomContentToLeft) // is on G Now page
&& getIntField(Common.WORKSPACE_INSTANCE, Fields.pvCurrentPage) == 0)
|| Common.LAUNCHER_CONTEXT.getResources().getConfiguration().orientation != Configuration.ORIENTATION_PORTRAIT) { // is not in portrait mode
widget.setVisibility(View.GONE);
updateWeatherContent();
} else {
widget.startAnimation(fadeOut);
}
}
});
CommonHooks.GetWorkspacePaddingListeners.add(new GetWorkspacePaddingHook());
CommonHooks.OnDragStartListeners.add(new XGELSCallback() {
@Override
public void onBeforeHookedMethod(MethodHookParam param) throws Throwable {
fadeOut(175);
}
});
CommonHooks.OnDragEndListeners.add(new XGELSCallback() {
@Override
public void onBeforeHookedMethod(MethodHookParam param) throws Throwable {
fadeIn(0);
}
});
XposedBridge.hookAllConstructors(findClass("com.google.android.search.shared.ui.ReverseDrawRestrictedLayout", lpparam.classLoader), new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ospc = (View) param.thisObject;
}
});
findAndHookMethod(Classes.Workspace, Methods.wUpdateStateForCustomContent, Integer.TYPE, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (widgetContentHolder == null ||
Common.LAUNCHER_CONTEXT.getResources().getConfiguration().orientation != Configuration.ORIENTATION_PORTRAIT) {
return;
}
widget.setVisibility(View.VISIBLE);
widget.setAlpha(1 - getFloatField(param.thisObject, Fields.wLastCustomContentScrollProgress));
widget.setTranslationY(ospc.getTranslationY());
}
});
findAndHookMethod(Classes.SearchPlate, Methods.spOnModeChanged, Integer.TYPE, Integer.TYPE, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if ((Integer) param.args[0] > 0) {
fadeOut(0);
} else {
if ((Integer) param.args[1] != 6 && (Integer) param.args[1] != 2) {
fadeIn(500);
}
}
}
});
CommonHooks.EnterOverviewModeListeners.add(new XGELSCallback() {
@Override
public void onBeforeHookedMethod(MethodHookParam param) throws Throwable {
fadeOut(0);
}
@Override
public void onAfterHookedMethod(MethodHookParam param) throws Throwable {
fadeOut(0);
}
});
findAndHookMethod(Classes.Launcher, Methods.lShowWorkspace, boolean.class, Runnable.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
fadeIn(1000);
}
});
}
}
}
public static void fadeOut(int duration) {
ViewGroup parent = (ViewGroup) ((ViewGroup) getObjectField(Common.LAUNCHER_INSTANCE, Fields.lSearchDropTargetBar)).getParent();
if (parent.getTag() != null) {
ViewGroup widget = (ViewGroup) parent.getTag();
widget.animate().alpha(0.0f).setDuration(duration).start();
}
}
public static void fadeIn(int startDelay) {
ViewGroup parent = (ViewGroup) ((ViewGroup) getObjectField(Common.LAUNCHER_INSTANCE, Fields.lSearchDropTargetBar)).getParent();
if (parent.getTag() != null) {
ViewGroup widget = (ViewGroup) parent.getTag();
widget.animate().alpha(1.0f).setDuration(200).setStartDelay(startDelay).start();
}
}
private static void updateWeatherContent() {
for (int i = 0; i < widgetContentHolder.getChildCount(); i++) {
View item = widgetContentHolder.getChildAt(i);
if (isCity(item)) {
((TextView) item).setText(getCity());
} else if (isTemperature(item)) {
((TextView) item).setText(getTemperatur());
} else if (isWeatherDescription(item)) {
((TextView) item).setText(getWeatherDescription());
}
}
}
private static String getWeatherDescription() {
return (String) callMethod(weatherEntry, Methods.wpGetWeatherDescription);
}
private static String getTemperatur() {
return callMethod(weatherEntry, Methods.wpGetTemperatur) + widgetSettings.unit;
}
private static String getCity() {
return (String) callMethod(weatherEntry, "getLocation");
}
public static void maybeAddWidget() {
ViewGroup searchDropTargetBar = ((ViewGroup) getObjectField(Common.LAUNCHER_INSTANCE, Fields.lSearchDropTargetBar));
ViewGroup parent = (ViewGroup) searchDropTargetBar.getParent();
if (parent.getTag() != null) {
widget = (LinearLayout) parent.getTag();
} else {
addWeatherWidget(searchDropTargetBar);
}
}
private static void addWeatherWidget(ViewGroup searchBar) {
ViewGroup parent = ((ViewGroup) searchBar.getParent());
widget = (LinearLayout) LayoutInflater.from(Common.XGELS_CONTEXT).inflate(R.layout.qsb_weather_widget, null, true);
widget.setPadding(searchBar.getPaddingLeft(), searchBar.getHeight() - Utils.dpToPx(8), searchBar.getPaddingRight(), parent.getPaddingBottom());
widgetContentHolder = (LinearLayout) widget.findViewById(R.id.weathercontentview);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) widgetContentHolder.getLayoutParams();
layoutParams.gravity = widgetSettings.gravity;
widgetContentHolder.setLayoutParams(layoutParams);
for (int i = 0; i < widgetSettings.contents.size(); i++) {
int content = widgetSettings.contents.get(i);
if ((content & WidgetSettings.TEXTVIEW) == WidgetSettings.TEXTVIEW) {
widgetContentHolder.addView(getTextView(widgetSettings, content));
}
if (i != widgetSettings.contents.size() - 1) {
widgetContentHolder.addView(getDivider(widgetSettings));
}
}
parent.setTag(widget);
parent.addView(widget);
}
private static boolean isTemperature(View view) {
return (((Integer) view.getTag()) & WidgetSettings.TEXTMASK) == WidgetSettings.CONTENT_TEMPERATURE;
}
private static boolean isCity(View view) {
return (((Integer) view.getTag()) & WidgetSettings.TEXTMASK) == WidgetSettings.CONTENT_CITY;
}
private static boolean isWeatherDescription(View view) {
return (((Integer) view.getTag()) & WidgetSettings.TEXTMASK) == WidgetSettings.CONTENT_WEATHER_DESCRIPTION;
}
private static View getDivider(WidgetSettings widgetSettings) {
TextView divider = getTextView(widgetSettings, WidgetSettings.DIVIDER);
divider.setText(" " + widgetSettings.divider + " ");
return divider;
}
private static TextView getTextView(WidgetSettings widgetSettings, int content) {
TextView textView = new TextView(Common.XGELS_CONTEXT);
textView.setTag(content);
textView.setTextColor(widgetSettings.textColor);
if (widgetSettings.textSize != -1) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
}
if (widgetSettings.textShadow) {
textView.setShadowLayer(2f, 1f, 1f, Color.BLACK);
}
if (widgetSettings.fillParent) {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1f);
textView.setLayoutParams(lp);
}
return textView;
}
public static class WidgetSettings {
public static final int TEXTVIEW = 0x80;
public static final int DIVIDER = 0x100;
public static final int TEXTMASK = 0xFF;
public static final int CONTENT_CITY = 0x81;
public static final int CONTENT_WEATHER_DESCRIPTION = 0x82;
public static final int CONTENT_TEMPERATURE = 0x83;
String divider, unit;
boolean fillParent, textShadow;
int gravity = Gravity.END, textSize = 10, textColor = Color.WHITE;
ArrayList<Integer> contents = new ArrayList<Integer>();
public WidgetSettings() {
String settings =
"gravity=" + Gravity.CENTER_HORIZONTAL + "|" +
"fillparent=" + Boolean.toString(false) + "|" +
"textSize=" + "" + -1 + "|" +
"textShadow=" + "" + Boolean.toString(true) + "|" +
"textColor=" + "" + Color.WHITE + "|" +
"divider=" + "-" + "|" +
"contents=" + CONTENT_CITY + "#" + CONTENT_WEATHER_DESCRIPTION + "#" + CONTENT_TEMPERATURE;
this.unit = getDefaultUnit();
for (String setting : settings.split("\\|")) {
if (setting.startsWith("gravity=")) {
this.gravity = Integer.parseInt(setting.split("=")[1]);
} else if (setting.startsWith("fillparent=")) {
this.fillParent = Boolean.parseBoolean(setting.split("=")[1]);
} else if (setting.startsWith("textSize=")) {
this.textSize = Integer.parseInt(setting.split("=")[1]);
} else if (setting.startsWith("textShadow=")) {
this.textShadow = Boolean.parseBoolean(setting.split("=")[1]);
} else if (setting.startsWith("textColor=")) {
this.textColor = Integer.parseInt(setting.split("=")[1]);
} else if (setting.startsWith("divider=")) {
this.divider = setting.split("=")[1];
} else if (setting.startsWith("unit=")) {
this.unit = setting.split("=")[1];
} else if (setting.startsWith("contents=")) {
for (String content : setting.replace("contents=", "").split("#")) {
contents.add(Integer.parseInt(content));
}
}
}
}
public String getDefaultUnit() {
String countryCode = Locale.getDefault().getCountry();
if ("US".equals(countryCode) // USA
|| "LR".equals(countryCode) // liberia
|| "MM".equals(countryCode)) {// burma
return "F";
}
return "C";
}
}
}