From 39d50574aa0e97b4e8be3c6e795264b4db7c1fec Mon Sep 17 00:00:00 2001 From: serso Date: Wed, 6 Jan 2016 14:33:13 +0100 Subject: [PATCH] Widgets refactor --- app/src/main/AndroidManifest.xml | 84 ------- .../org/solovyev/android/calculator/App.java | 59 ++--- .../CalculatorActivityLauncher.java | 39 ++-- .../android/calculator/CalculatorButtons.java | 18 -- .../calculator/CalculatorReceiver.java | 19 +- .../android/calculator/Preferences.java | 36 +-- .../calculator/view/TextHighlighter.java | 11 +- .../widget/BaseCalculatorWidgetProvider.java | 208 ------------------ .../calculator/widget/CalculatorWidget.java | 201 ++++++++++++++++- ...CalculatorWidgetConfigurationActivity.java | 33 --- .../widget/CalculatorWidgetProvider.java | 31 --- .../widget/CalculatorWidgetProvider3x4.java | 31 --- .../widget/CalculatorWidgetProvider4x4.java | 31 --- .../widget/CalculatorWidgetProvider4x5.java | 31 --- app/src/main/res/values/ids.xml | 2 + .../main/res/xml/calculator_widget_info.xml | 34 --- .../res/xml/calculator_widget_info_3x3.xml | 32 --- .../res/xml/calculator_widget_info_3x4.xml | 32 --- .../res/xml/calculator_widget_info_4x4.xml | 36 --- .../res/xml/calculator_widget_info_4x5.xml | 34 --- 20 files changed, 273 insertions(+), 729 deletions(-) delete mode 100644 app/src/main/java/org/solovyev/android/calculator/widget/BaseCalculatorWidgetProvider.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetConfigurationActivity.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider3x4.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x4.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x5.java delete mode 100644 app/src/main/res/xml/calculator_widget_info.xml delete mode 100644 app/src/main/res/xml/calculator_widget_info_3x3.xml delete mode 100644 app/src/main/res/xml/calculator_widget_info_3x4.xml delete mode 100644 app/src/main/res/xml/calculator_widget_info_4x4.xml delete mode 100644 app/src/main/res/xml/calculator_widget_info_4x5.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9dbff231..c99831e9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -139,14 +139,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > OLD_WIDGETS = Arrays.asList(CalculatorWidgetProvider.class, CalculatorWidgetProvider3x4.class, CalculatorWidgetProvider4x4.class, CalculatorWidgetProvider4x5.class); + public static String subTag(@Nonnull String subTag) { + return sub(TAG, subTag); + } + + @NonNull + public static String sub(@Nonnull String tag, @Nonnull String subTag) { + return tag + "/" + subTag; + } + @Nonnull private static final Products products = Products.create().add(ProductTypes.IN_APP, Arrays.asList("ad_free")); @Nonnull @@ -145,21 +149,6 @@ public final class App { App.broadcaster = new CalculatorBroadcaster(application, preferences); App.vibrator = new Vibrator(application, preferences); App.screenMetrics = new ScreenMetrics(application); - - final List> oldNotUsedWidgetClasses = findNotUsedWidgets(application); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { - for (Class oldNotUsedWidgetClass : oldNotUsedWidgetClasses) { - Android.enableComponent(application, oldNotUsedWidgetClass, false); - } - } else { - // smaller widgets should be still used for smaller screens - if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x5.class)) { - Android.enableComponent(application, CalculatorWidgetProvider4x5.class, false); - } - if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x4.class)) { - Android.enableComponent(application, CalculatorWidgetProvider4x4.class, false); - } - } App.languages.init(App.preferences); App.initialized = true; @@ -168,21 +157,6 @@ public final class App { } } - @Nonnull - private static List> findNotUsedWidgets(@Nonnull Application application) { - final List> result = new ArrayList<>(); - - final AppWidgetManager widgetManager = AppWidgetManager.getInstance(application); - for (Class widgetClass : OLD_WIDGETS) { - final int ids[] = widgetManager.getAppWidgetIds(new ComponentName(application, widgetClass)); - if (ids == null || ids.length == 0) { - result.add(widgetClass); - } - } - - return result; - } - private static void checkInit() { if (!initialized) { throw new IllegalStateException("App should be initialized!"); @@ -319,4 +293,9 @@ public final class App { // Create and show the dialog. dialogFragment.show(ft, fragmentTag); } + + @NonNull + public static String toColorString(@ColorInt int color) { + return Integer.toHexString(color).substring(2); + } } diff --git a/app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java b/app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java index f1ba3a39..b8d19118 100644 --- a/app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java +++ b/app/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java @@ -29,20 +29,16 @@ import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.preference.PreferenceManager; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; - -import org.solovyev.android.Android; +import jscl.math.Generic; +import org.solovyev.android.Activities; import org.solovyev.android.calculator.about.CalculatorAboutActivity; import org.solovyev.android.calculator.function.FunctionEditDialogFragment; import org.solovyev.android.calculator.history.CalculatorHistoryActivity; -import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity; -import org.solovyev.android.calculator.math.edit.CalculatorOperatorsActivity; -import org.solovyev.android.calculator.math.edit.CalculatorVarsActivity; -import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment; -import org.solovyev.android.calculator.math.edit.VarEditDialogFragment; +import org.solovyev.android.calculator.math.edit.*; import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity; import org.solovyev.android.calculator.plot.CalculatorPlotActivity; import org.solovyev.android.calculator.plot.CalculatorPlotter; @@ -51,12 +47,9 @@ import org.solovyev.common.msg.Message; import org.solovyev.common.msg.MessageType; import org.solovyev.common.text.Strings; -import java.util.List; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - -import jscl.math.Generic; +import java.util.List; /** * User: serso @@ -74,7 +67,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener public static void showHistory(@Nonnull final Context context, boolean detached) { final Intent intent = new Intent(context, CalculatorHistoryActivity.class); - Android.addIntentFlags(intent, detached, context); + Activities.addIntentFlags(intent, detached, context); context.startActivity(intent); } @@ -84,7 +77,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener public static void showSettings(@Nonnull final Context context, boolean detached) { final Intent intent = new Intent(context, PreferencesActivity.class); - Android.addIntentFlags(intent, detached, context); + Activities.addIntentFlags(intent, detached, context); context.startActivity(intent); } @@ -98,7 +91,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener public static void showFunctions(@Nonnull final Context context, boolean detached) { final Intent intent = new Intent(context, CalculatorFunctionsActivity.class); - Android.addIntentFlags(intent, detached, context); + Activities.addIntentFlags(intent, detached, context); context.startActivity(intent); } @@ -108,7 +101,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener public static void showOperators(@Nonnull final Context context, boolean detached) { final Intent intent = new Intent(context, CalculatorOperatorsActivity.class); - Android.addIntentFlags(intent, detached, context); + Activities.addIntentFlags(intent, detached, context); context.startActivity(intent); } @@ -118,14 +111,14 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener public static void showVars(@Nonnull final Context context, boolean detached) { final Intent intent = new Intent(context, CalculatorVarsActivity.class); - Android.addIntentFlags(intent, detached, context); + Activities.addIntentFlags(intent, detached, context); context.startActivity(intent); } public static void plotGraph(@Nonnull final Context context) { final Intent intent = new Intent(); intent.setClass(context, CalculatorPlotActivity.class); - Android.addIntentFlags(intent, false, context); + Activities.addIntentFlags(intent, false, context); context.startActivity(intent); } @@ -136,12 +129,12 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener final String varValue = viewState.getText(); if (!Strings.isEmpty(varValue)) { if (CalculatorVarsFragment.isValidValue(varValue)) { - if (context instanceof ActionBarActivity) { - VarEditDialogFragment.showDialog(VarEditDialogFragment.Input.newFromValue(varValue), ((ActionBarActivity) context).getSupportFragmentManager()); + if (context instanceof AppCompatActivity) { + VarEditDialogFragment.showDialog(VarEditDialogFragment.Input.newFromValue(varValue), ((AppCompatActivity) context).getSupportFragmentManager()); } else { final Intent intent = new Intent(context, CalculatorVarsActivity.class); intent.putExtra(CalculatorVarsFragment.CREATE_VAR_EXTRA_STRING, varValue); - Android.addIntentFlags(intent, false, context); + Activities.addIntentFlags(intent, false, context); context.startActivity(intent); } } else { @@ -208,7 +201,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener public static void likeButtonPressed(@Nonnull final Context context) { final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.cpp_share_link))); - Android.addIntentFlags(intent, false, context); + Activities.addIntentFlags(intent, false, context); context.startActivity(intent); } @@ -250,7 +243,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener @Override public void run() { final Intent intent = new Intent(context, CalculatorMatrixActivity.class); - Android.addIntentFlags(intent, false, context); + Activities.addIntentFlags(intent, false, context); context.startActivity(intent); } }); diff --git a/app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java b/app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java index dd34b3ab..73783e1e 100644 --- a/app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java +++ b/app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java @@ -33,7 +33,6 @@ import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.widget.Button; -import android.widget.RemoteViews; import jscl.AngleUnit; import jscl.NumeralBase; import org.solovyev.android.Views; @@ -48,11 +47,6 @@ import org.solovyev.android.views.dragbutton.SimpleDragListener; import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** - * User: serso - * Date: 9/28/12 - * Time: 12:06 AM - */ public final class CalculatorButtons { private CalculatorButtons() { @@ -87,10 +81,6 @@ public final class CalculatorButtons { } } - public static void initMultiplicationButton(@Nonnull RemoteViews views) { - views.setTextViewText(R.id.cpp_button_multiplication, Locator.getInstance().getEngine().getMultiplicationSign()); - } - public static void toggleEqualsButton(@Nullable SharedPreferences preferences, @Nonnull Activity activity) { @@ -114,14 +104,6 @@ public final class CalculatorButtons { } } - /* - ********************************************************************** - * - * STATIC CLASSES - * - ********************************************************************** - */ - @Nonnull private static CalculatorKeyboard getKeyboard() { return Locator.getInstance().getKeyboard(); diff --git a/app/src/main/java/org/solovyev/android/calculator/CalculatorReceiver.java b/app/src/main/java/org/solovyev/android/calculator/CalculatorReceiver.java index ac7b3ec5..aaba484f 100644 --- a/app/src/main/java/org/solovyev/android/calculator/CalculatorReceiver.java +++ b/app/src/main/java/org/solovyev/android/calculator/CalculatorReceiver.java @@ -3,6 +3,7 @@ package org.solovyev.android.calculator; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.text.TextUtils; import javax.annotation.Nonnull; @@ -22,14 +23,16 @@ public final class CalculatorReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - - if (ACTION_BUTTON_PRESSED.equals(action)) { - final int buttonId = intent.getIntExtra(ACTION_BUTTON_ID_EXTRA, 0); - - final CalculatorButton button = CalculatorButton.getById(buttonId); - if (button != null) { - button.onClick(); - } + if (!TextUtils.equals(action, ACTION_BUTTON_PRESSED)) { + return; } + + final int buttonId = intent.getIntExtra(ACTION_BUTTON_ID_EXTRA, 0); + final CalculatorButton button = CalculatorButton.getById(buttonId); + if (button == null) { + return; + } + + button.onClick(); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/Preferences.java b/app/src/main/java/org/solovyev/android/calculator/Preferences.java index b8133fc5..8c2c7532 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Preferences.java +++ b/app/src/main/java/org/solovyev/android/calculator/Preferences.java @@ -26,35 +26,28 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.res.TypedArray; import android.graphics.Color; +import android.support.annotation.ColorRes; import android.support.annotation.LayoutRes; import android.support.annotation.StyleRes; import android.util.SparseArray; import android.view.ContextThemeWrapper; - +import jscl.AngleUnit; +import jscl.NumeralBase; import org.solovyev.android.Check; import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.preferences.PurchaseDialogActivity; import org.solovyev.android.calculator.wizard.WizardActivity; -import org.solovyev.android.prefs.BooleanPreference; -import org.solovyev.android.prefs.IntegerPreference; -import org.solovyev.android.prefs.LongPreference; -import org.solovyev.android.prefs.NumberToStringPreference; -import org.solovyev.android.prefs.Preference; -import org.solovyev.android.prefs.StringPreference; +import org.solovyev.android.prefs.*; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.text.DecimalFormatSymbols; import java.util.EnumMap; import java.util.Locale; import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import jscl.AngleUnit; -import jscl.NumeralBase; - import static org.solovyev.android.Android.isPhoneModel; import static org.solovyev.android.DeviceModel.samsung_galaxy_s; import static org.solovyev.android.DeviceModel.samsung_galaxy_s_2; @@ -156,7 +149,7 @@ public final class Preferences { default_theme(0, 0, null), metro_blue_theme(R.layout.onscreen_layout, R.layout.widget_layout, Gui.Theme.metro_blue_theme), material_theme(R.layout.onscreen_layout_material, R.layout.widget_layout_material, Gui.Theme.material_theme), - material_light_theme(R.layout.onscreen_layout_material_light, R.layout.widget_layout_material_light, Gui.Theme.material_light_theme); + material_light_theme(R.layout.onscreen_layout_material_light, R.layout.widget_layout_material_light, Gui.Theme.material_light_theme, true); @LayoutRes private final int onscreenLayout; @@ -167,13 +160,20 @@ public final class Preferences { @Nullable private final Gui.Theme appTheme; + private final boolean light; + @Nonnull private final Map cache = new EnumMap<>(Gui.Theme.class); SimpleTheme(int onscreenLayout, int widgetLayout, @Nullable Gui.Theme appTheme) { + this(onscreenLayout, widgetLayout, appTheme, false); + } + + SimpleTheme(int onscreenLayout, int widgetLayout, @Nullable Gui.Theme appTheme, boolean light) { this.onscreenLayout = onscreenLayout; this.widgetLayout = widgetLayout; this.appTheme = appTheme; + this.light = light; } public int getOnscreenLayout(@Nonnull Gui.Theme appTheme) { @@ -220,6 +220,14 @@ public final class Preferences { public Gui.Theme getAppTheme() { return appTheme; } + + @ColorRes + public int getDisplayTextColor(boolean error) { + if (error) { + return light ? R.color.cpp_text_inverse_error : R.color.cpp_text_error; + } + return light ? R.color.cpp_text_inverse : R.color.cpp_text; + } } public static class Widget { diff --git a/app/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java b/app/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java index 11eeb9a2..4802e561 100644 --- a/app/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java +++ b/app/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java @@ -22,20 +22,15 @@ package org.solovyev.android.calculator.view; -import org.solovyev.android.calculator.AbstractNumberBuilder; -import org.solovyev.android.calculator.CalculatorParseException; -import org.solovyev.android.calculator.LiteNumberBuilder; -import org.solovyev.android.calculator.Locator; -import org.solovyev.android.calculator.NumberBuilder; +import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessorEditorResult; import org.solovyev.common.MutableObject; -import java.util.Map; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Map; /** * User: serso @@ -227,6 +222,6 @@ public class TextHighlighter implements TextProcessor getComponentClass() { - return this.getClass(); - } - - private void updateWidget(@Nonnull Context context, - @Nonnull AppWidgetManager appWidgetManager, - @Nonnull int[] appWidgetIds) { - final CalculatorEditorViewState editorState = Locator.getInstance().getEditor().getViewState(); - final CalculatorDisplayViewState displayState = Locator.getInstance().getDisplay().getViewState(); - - final Resources resources = context.getResources(); - final Preferences.SimpleTheme theme = App.getWidgetTheme().resolveThemeFor(App.getTheme()); - for (int appWidgetId : appWidgetIds) { - final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout(appWidgetManager, appWidgetId, resources, theme)); - - for (CalculatorButton button : CalculatorButton.values()) { - final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, button.getButtonId(), newButtonClickedIntent(context, button), PendingIntent.FLAG_UPDATE_CURRENT); - if (pendingIntent != null) { - views.setOnClickPendingIntent(button.getButtonId(), pendingIntent); - } - } - - updateEditorState(context, views, editorState); - updateDisplayState(context, views, displayState, theme); - - CalculatorButtons.initMultiplicationButton(views); - - appWidgetManager.updateAppWidget(appWidgetId, views); - } - } - - private int getLayout(@Nonnull AppWidgetManager appWidgetManager, int appWidgetId, @Nonnull Resources resources, @Nonnull Preferences.SimpleTheme theme) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - return getLayoutJellyBean(appWidgetManager, appWidgetId, resources, theme); - } - return theme.getWidgetLayout(App.getTheme()); - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private int getLayoutJellyBean(@Nonnull AppWidgetManager appWidgetManager, int appWidgetId, Resources resources, @Nonnull Preferences.SimpleTheme theme) { - final Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); - - if (options != null) { - // Get the value of OPTION_APPWIDGET_HOST_CATEGORY - final int category = options.getInt(OPTION_APPWIDGET_HOST_CATEGORY, -1); - - if (category != -1) { - // If the value is WIDGET_CATEGORY_KEYGUARD, it's a lockscreen widget - final boolean keyguard = category == WIDGET_CATEGORY_KEYGUARD; - if (keyguard) { - final int minHeightDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, -1); - final int minHeight = resources.getDimensionPixelSize(R.dimen.min_expanded_height_lock_screen); - final boolean expanded = (minHeightDp >= minHeight / resources.getDisplayMetrics().density); - if (expanded) { - return R.layout.widget_layout_lockscreen; - } else { - return R.layout.widget_layout_lockscreen_collapsed; - } - } - } - } - return theme.getWidgetLayout(App.getTheme()); - } - - @Override - public void onReceive(@Nonnull Context context, @Nonnull Intent intent) { - super.onReceive(context, intent); - - final String action = intent.getAction(); - if (ACTION_CONFIGURATION_CHANGED.equals(action)) { - updateState(context); - } else if (ACTION_EDITOR_STATE_CHANGED.equals(action)) { - updateState(context); - } else if (ACTION_DISPLAY_STATE_CHANGED.equals(action)) { - updateState(context); - } else if (ACTION_APPWIDGET_OPTIONS_CHANGED.equals(action)) { - updateState(context); - } else if (ACTION_THEME_CHANGED.equals(action)) { - updateState(context); - } - } - - private void updateDisplayState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorDisplayViewState displayState, @Nonnull Preferences.SimpleTheme theme) { - final Resources resources = context.getResources(); - if (displayState.isValid()) { - views.setTextViewText(R.id.calculator_display, displayState.getText()); - views.setTextColor(R.id.calculator_display, resources.getColor(theme == Preferences.SimpleTheme.material_light_theme ? R.color.cpp_text_inverse : R.color.cpp_text)); - } else { - views.setTextColor(R.id.calculator_display, resources.getColor(theme == Preferences.SimpleTheme.material_light_theme ? R.color.cpp_text_inverse_error : R.color.cpp_text_error)); - } - } - - private void updateEditorState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorEditorViewState editorState) { - final CharSequence text = editorState.getTextAsCharSequence(); - - CharSequence newText = text; - int selection = editorState.getSelection(); - if (selection >= 0 && selection <= text.length()) { - // inject cursor - newText = Html.fromHtml(text.subSequence(0, selection) + "|" + text.subSequence(selection, text.length())); - } - Locator.getInstance().getNotifier().showDebugMessage(TAG, "New editor state: " + text); - views.setTextViewText(R.id.calculator_editor, newText); - } -} diff --git a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidget.java b/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidget.java index 8e7695ad..8b58d6ea 100644 --- a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidget.java +++ b/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidget.java @@ -1,4 +1,203 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + package org.solovyev.android.calculator.widget; -public class CalculatorWidget extends BaseCalculatorWidgetProvider { +import android.annotation.TargetApi; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.content.ContextCompat; +import android.text.Html; +import android.text.TextUtils; +import android.widget.RemoteViews; +import org.solovyev.android.Views; +import org.solovyev.android.calculator.*; +import org.solovyev.android.calculator.Preferences.SimpleTheme; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT; +import static android.content.Intent.ACTION_CONFIGURATION_CHANGED; +import static android.os.Build.VERSION_CODES.JELLY_BEAN; +import static org.solovyev.android.calculator.CalculatorBroadcaster.*; +import static org.solovyev.android.calculator.CalculatorReceiver.newButtonClickedIntent; + +public class CalculatorWidget extends AppWidgetProvider { + + private static final String TAG = App.subTag("Widget"); + private static final int WIDGET_CATEGORY_KEYGUARD = 2; + private static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory"; + private static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS"; + + @Nullable + private String cursorColor; + + public CalculatorWidget() { + } + + @Override + public void onEnabled(Context context) { + super.onEnabled(context); + initCursorColor(context); + } + + @Nonnull + private String getCursorColor(@Nonnull Context context) { + return initCursorColor(context); + } + + @Nonnull + private String initCursorColor(@Nonnull Context context) { + if (cursorColor == null) { + cursorColor = App.toColorString(ContextCompat.getColor(context, R.color.cpp_widget_cursor)); + } + return cursorColor; + } + + @Override + public void onUpdate(@Nonnull Context context, + @Nonnull AppWidgetManager appWidgetManager, + @Nonnull int[] appWidgetIds) { + super.onUpdate(context, appWidgetManager, appWidgetIds); + + updateWidget(context, appWidgetManager, appWidgetIds); + } + + public void updateState(@Nonnull Context context) { + final AppWidgetManager manager = AppWidgetManager.getInstance(context); + final int[] widgetIds = manager.getAppWidgetIds(new ComponentName(context, CalculatorWidget.class)); + updateWidget(context, manager, widgetIds); + } + + private void updateWidget(@Nonnull Context context, + @Nonnull AppWidgetManager manager, + @Nonnull int[] widgetIds) { + final CalculatorEditorViewState editorState = Locator.getInstance().getEditor().getViewState(); + final CalculatorDisplayViewState displayState = Locator.getInstance().getDisplay().getViewState(); + + final Resources resources = context.getResources(); + final SimpleTheme theme = App.getWidgetTheme().resolveThemeFor(App.getTheme()); + for (int widgetId : widgetIds) { + final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout(manager, widgetId, resources, theme)); + + for (CalculatorButton button : CalculatorButton.values()) { + final PendingIntent intent = PendingIntent.getBroadcast(context, button.getButtonId(), newButtonClickedIntent(context, button), PendingIntent.FLAG_UPDATE_CURRENT); + if (intent != null) { + views.setOnClickPendingIntent(button.getButtonId(), intent); + } + } + + updateEditorState(context, views, editorState); + updateDisplayState(context, views, displayState, theme); + + views.setTextViewText(R.id.cpp_button_multiplication, Locator.getInstance().getEngine().getMultiplicationSign()); + + manager.updateAppWidget(widgetId, views); + } + } + + private int getLayout(@Nonnull AppWidgetManager manager, int widgetId, @Nonnull Resources resources, @Nonnull SimpleTheme theme) { + if (Build.VERSION.SDK_INT >= JELLY_BEAN) { + return getLayoutJellyBean(manager, widgetId, resources, theme); + } + return getDefaultLayout(theme); + } + + private int getDefaultLayout(@Nonnull SimpleTheme theme) { + return theme.getWidgetLayout(App.getTheme()); + } + + @TargetApi(JELLY_BEAN) + private int getLayoutJellyBean(@Nonnull AppWidgetManager manager, int widgetId, Resources resources, @Nonnull SimpleTheme theme) { + final Bundle options = manager.getAppWidgetOptions(widgetId); + if (options == null) { + return getDefaultLayout(theme); + } + + final int category = options.getInt(OPTION_APPWIDGET_HOST_CATEGORY, -1); + if (category == -1) { + return getDefaultLayout(theme); + } + + final boolean keyguard = category == WIDGET_CATEGORY_KEYGUARD; + if (!keyguard) { + return getDefaultLayout(theme); + } + + final int widgetMinHeight = Views.toPixels(resources.getDisplayMetrics(), options.getInt(OPTION_APPWIDGET_MIN_HEIGHT, 0)); + final int lockScreenMinHeight = resources.getDimensionPixelSize(R.dimen.min_expanded_height_lock_screen); + final boolean expanded = widgetMinHeight >= lockScreenMinHeight; + if (expanded) { + return R.layout.widget_layout_lockscreen; + } else { + return R.layout.widget_layout_lockscreen_collapsed; + } + } + + @Override + public void onReceive(@Nonnull Context context, @Nonnull Intent intent) { + super.onReceive(context, intent); + + final String action = intent.getAction(); + if (TextUtils.isEmpty(action)) { + return; + } + switch (action) { + case ACTION_CONFIGURATION_CHANGED: + case ACTION_EDITOR_STATE_CHANGED: + case ACTION_DISPLAY_STATE_CHANGED: + case ACTION_APPWIDGET_OPTIONS_CHANGED: + case ACTION_THEME_CHANGED: + updateState(context); + break; + } + } + + private void updateDisplayState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorDisplayViewState displayState, @Nonnull SimpleTheme theme) { + final boolean error = !displayState.isValid(); + if (!error) { + views.setTextViewText(R.id.calculator_display, displayState.getText()); + } + views.setTextColor(R.id.calculator_display, ContextCompat.getColor(context, theme.getDisplayTextColor(error))); + } + + private void updateEditorState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorEditorViewState editorState) { + final CharSequence text = editorState.getTextAsCharSequence(); + + CharSequence newText = text; + int selection = editorState.getSelection(); + if (selection >= 0 && selection <= text.length()) { + // inject cursor + newText = Html.fromHtml(text.subSequence(0, selection) + "|" + text.subSequence(selection, text.length())); + } + Locator.getInstance().getNotifier().showDebugMessage(TAG, "New editor state: " + text); + views.setTextViewText(R.id.calculator_editor, newText); + } } diff --git a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetConfigurationActivity.java b/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetConfigurationActivity.java deleted file mode 100644 index 2fff1205..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetConfigurationActivity.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.widget; - -import android.app.Activity; - -/** - * User: Solovyev_S - * Date: 19.10.12 - * Time: 16:20 - */ -public class CalculatorWidgetConfigurationActivity extends Activity { -} diff --git a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider.java b/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider.java deleted file mode 100644 index f8785be3..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.widget; - -/** - * User: serso - * Date: 11/18/12 - * Time: 1:00 PM - */ -public class CalculatorWidgetProvider extends BaseCalculatorWidgetProvider { -} diff --git a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider3x4.java b/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider3x4.java deleted file mode 100644 index 5e88bd60..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider3x4.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.widget; - -/** - * User: serso - * Date: 11/18/12 - * Time: 1:01 PM - */ -public class CalculatorWidgetProvider3x4 extends BaseCalculatorWidgetProvider { -} diff --git a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x4.java b/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x4.java deleted file mode 100644 index 459db813..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x4.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.widget; - -/** - * User: serso - * Date: 11/18/12 - * Time: 1:01 PM - */ -public class CalculatorWidgetProvider4x4 extends BaseCalculatorWidgetProvider { -} diff --git a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x5.java b/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x5.java deleted file mode 100644 index 4fac4dcd..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/widget/CalculatorWidgetProvider4x5.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.widget; - -/** - * User: serso - * Date: 11/18/12 - * Time: 7:43 PM - */ -public class CalculatorWidgetProvider4x5 extends BaseCalculatorWidgetProvider { -} diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 28b15f07..96c8994c 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -35,6 +35,8 @@ + + diff --git a/app/src/main/res/xml/calculator_widget_info.xml b/app/src/main/res/xml/calculator_widget_info.xml deleted file mode 100644 index 3c52ebd6..00000000 --- a/app/src/main/res/xml/calculator_widget_info.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - diff --git a/app/src/main/res/xml/calculator_widget_info_3x3.xml b/app/src/main/res/xml/calculator_widget_info_3x3.xml deleted file mode 100644 index 5bb78833..00000000 --- a/app/src/main/res/xml/calculator_widget_info_3x3.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - diff --git a/app/src/main/res/xml/calculator_widget_info_3x4.xml b/app/src/main/res/xml/calculator_widget_info_3x4.xml deleted file mode 100644 index 8593df5d..00000000 --- a/app/src/main/res/xml/calculator_widget_info_3x4.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - diff --git a/app/src/main/res/xml/calculator_widget_info_4x4.xml b/app/src/main/res/xml/calculator_widget_info_4x4.xml deleted file mode 100644 index b5fb3e9c..00000000 --- a/app/src/main/res/xml/calculator_widget_info_4x4.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - diff --git a/app/src/main/res/xml/calculator_widget_info_4x5.xml b/app/src/main/res/xml/calculator_widget_info_4x5.xml deleted file mode 100644 index 6f5d556a..00000000 --- a/app/src/main/res/xml/calculator_widget_info_4x5.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - \ No newline at end of file